このパートでは、文字列と値の組であるオブジェクトについて取り扱います。
レッスン1 オブジェクト
fluorite-7において、オブジェクトとは文字列から値を引くことができる辞書です。
何も定義されていない空のオブジェクトを作るには、{}
と記述します。
この演算子を、オブジェクト初期化子と呼びます。
$ fl7 '{}'
{}
レッスン2 プロパティの宣言
{
と}
の間で「キー:
値」と記述することでプロパティを宣言できます。
$ fl7 '{a: 10}'
{a:10}
プロパティは;
で区切ることで複数宣言できます。
;
は無駄に大量に並べても、単に無視されます。
$ fl7 '{a: 10; b: 200}'
{a:10;b:200}
$ fl7 '{;;;a: 10;;; b: 200;;;}'
{a:10;b:200}
キーに識別子を書いた場合はその識別子の名前がキーになりますが、そうでない場合はその式が評価されてキーとなります。
$ fl7 '{"#": 10}'
{#:10}
$ fl7 '{"a" & "b": 10}'
{ab:10}
$ fl7 'k: "a"; {(k): 10}'
{a:10}
レッスン3 プロパティへのアクセス
「オブジェクト.
識別子」もしくは「オブジェクト[
文字列]
」でオブジェクトのプロパティにアクセスします。
$ fl7 '{a: 10; b: 200}.b'
200
$ fl7 '{a: 10; b: 200}["b"]'
200
[
]
によるアクセスは文字列であることに気を付けてください。
その場所に識別子を書いたとき、その名前が既に使用済みであれば、その名前が示す値がキーとして使われます。
$ fl7 'a: "b"; {a: 10; b: 200}[a]'
200
また、「オブジェクト."
キー"
」のように書くと、こちらでも文字列による指定ができます。
$ fl7 '{ab: 10}.ab'
10
$ fl7 '{ab: 10}."ab"'
10
$ fl7 '{ab: 10}.("a" & "b")'
10
存在しないキーにアクセスすると、NULLが返されます。
$ fl7 '{a: 10}.b'
NULL
レッスン4 オブジェクトの継承
fluorite-7のオブジェクトは継承することができます。
継承するには、「オブジェクト{
}
」と記述します。
継承したオブジェクトに対して.
でアクセスをすると、親オブジェクトのプロパティも見えるようになります。
$ fl7 '{a: 10}{b: 200}.a'
10
親オブジェクトと同じ名前のプロパティがあった場合は、子オブジェクトのプロパティが優先されます。
$ fl7 '{a: 10}{a: 200}.a'
200
一方、[
]
によるアクセスは継承を考慮しません。
$ fl7 '{a: 10}{b: 200}["a"]'
NULL
継承を考慮したプロパティのアクセスをメンバアクセス、.
をメンバアクセス演算子と呼びます。
レッスン5 オブジェクトのストリーマ展開
オブジェクトをストリーマ展開すると、そのオブジェクトのプロパティのストリーマが得られます。
親オブジェクトのプロパティは参照しません。
$ fl7 '{a: 10}{b: 200; c: 4}[]'
{key:b;value:200}
{key:c;value:4}
レッスン6 オブジェクトの文字列化
オブジェクトを文字列化すると、継承を無視したプロパティの一覧が得られます。
$ fl7 '&{a: 10}{b: 200; c: 4}'
{b:200;c:4}
レッスン7 プロパティのストリーマからのオブジェクト構築
演算子{[
]}
は、プロパティのストリーマからオブジェクトを構築します。
$ fl7 '{[ {key:A;value:B},{key:C;value:D} ]}'
{A:B;C:D}
丁度ストリーマ展開と逆の操作です。
レッスン8 宣言されたプロパティへの参照
オブジェクト初期化子の中で「識別子:
」によって定義されたプロパティは、そのオブジェクト初期化子の中から名前で呼べるようになります。
$ fl7 '{y: x * 20; x: 3; z: x + y}'
{y:60;x:3;z:63}
整形してみましょう。
{
y: x * 20;
x: 3;
z: x + y;
}
見ての通り、y
の値はx
に依存し、z
の値はx
とy
に依存します。
このプロパティはx
→y
→z
の順番でセットしなければなりませんが、実際そのような順番でセットされます。
オブジェクト初期化子がオブジェクトを初期化する過程において、この依存関係は循環してはなりません。
例えば次のようなものは循環が起こります。
$ fl7 '{x: x}'
x
を初期化するにはx
が必要ですが、そのx
を初期化するためにx
が必要です。
オブジェクト初期化子がオブジェクトを初期化する過程において、この依存関係は循環してはなりません。
しかし、「オブジェクトを初期化する過程」でなければ循環してもかまいません。
$ fl7 '{f: () -> f}'
{f:[FluoriteFunction]}
これは評価すると関数f
が返ってくる関数f
が定義されたオブジェクトです。
このように名前の参照が遅延される場合であれば、自由に名前を利用することができます。
レッスン9 プロパティ初期化における代入と即席代入
オブジェクト初期化子の中でプロパティが名前で直接呼べるようになることは、良いことばかりではありません。
既存の変数と同名のプロパティを作る状況はよくあることです。
そういう状況の為に、代入というプロパティ初期化の方法があります。
代入によるプロパティ初期化を行うには、:
の代わりに=
を使用します。
$ fl7 'x: 5; {x = x}'
{x:5}
x: x
では循環参照のエラーになっていたものが、x = x
では正しくx
というキーに変数x
の中身がセットされました。
更に、値部分が1個の識別子のみで、キーがその識別子と同じ場合、即席代入を使うことができます。
即席代入は、もはや=
も書かず、単にその識別子を記述するだけです。
$ fl7 'x: 5; {x}'
{x:5}
$ fl7 'p: k, v -> {k; v}; p("a"; 50)'
{k:a;v:50}
まとめ
-
{
}
でオブジェクトを作る。 -
key: value
でプロパティを宣言。 - プロパティは
;
で区切って複数初期化できる。 -
object{}
で継承つきオブジェクトを生成。 -
object.identifier
でメンバアクセス。 - メンバアクセスは継承を考慮する。
-
object[string]
で通常のプロパティアクセス。 -
object[]
でプロパティのストリーマを得る。 -
{[
]}
でプロパティのストリーマから構築。 -
key = value
はプロパティの代入。 -
identifier
はプロパティの即席代入。 - キーが識別子の宣言は、同じオブジェクト初期化子の中から名前で呼べるようになる。
- オブジェクト初期化時に依存関係が循環するように名前を参照することはできない。