ハッシュと値の入れ子(Tc600-3以降)¶
Tc600-3 以降では、値の型にハッシュ(連想配列)が加わった。また、配列やハッシュの要素に配列やハッシュを入れる(入れ子)ことと、要素の要素へ直接代入する(多次元代入)ことができるようになった。
500 系からの互換性に関わる変更は 600 での変更点 を参照。
ハッシュ¶
生成¶
ハッシュは IHASH で作る。キーと値を交互に並べる。IHASH() は空のハッシュになる。
_h = IHASH("name", "さくら", "age", 16)
_e = IHASH()
文字列から作るときは HASH_SPLIT を使う。
_h = HASH_SPLIT("a=1,b=2", ",", "=")
ハッシュの変数は、IHASH などで最初にハッシュとして作っておく必要がある。未定義の変数に _x["a"] = 1 と書いても、ハッシュではなく汎用配列の扱いになる("a" は数値として 0 番目と解釈される)。
要素の参照・代入¶
h[キー] で値を読み、h[キー] = 値 で追加・上書きする。
_h = IHASH()
_h["name"] = "さくら"
_h["name"] // "さくら"
_h["none"] // "" (キーが無いときは空文字列)
_h["age"] += 1 // 複合代入も使える
- キーが無いときは空文字列を返す。VOID ではない
- 値には配列やハッシュも入れられる(入れ子)
- 序数の2番目以降(範囲指定やデリミタ)は無視される。範囲つきの読み出し
h[a, b]は空文字列になる
キーの一致¶
スカラーのキーは「数値」と「文字列」に分けて比べる。
- 数値として扱うもの: 整数、実数、正規形の整数を表す文字列(
"9"、"-3"など)"09"、"-0"、"+1"、" 1"、64bit に収まらない数字列は文字列として扱う
- 数値同士は値で比べる。整数と実数も誤差なく比べる
- 文字列同士は文字列として比べる。VOID は空文字列と同じキーになる
このため、h[1]、h["1"]、h[1.0] はすべて同じキーになる。一方、h[1.5] と h["1.5"]、h[0] と h["-0"] は別のキーになる。
同じキーとみなされる値を複数回 IHASH に渡したときは、最初のキーと値が残る。
IHASH(9, "i9", "9", "s9") // 9=i9 だけ
並び順¶
ハッシュの要素はキーの順に並ぶ。挿入した順ではない。HASH_KEYS、HASH_VALUES、文字列化、foreach、セーブファイルの並びはすべてこの順になる。
- 数値 < 文字列 の順に並ぶ。数値同士は値の順、文字列同士は文字列の順
- キーが配列やハッシュのときは、スカラー < 配列 < ハッシュ の順に並び、配列同士・ハッシュ同士は先頭の要素から順に比べる
_h = IHASH(10,1, 9,1, 100,1, -1,1, "b",1, "B",1, 2.5,1)
HASH_KEYS(_h) // -1,2.5,9,10,100,B,b
値としての振る舞い¶
| 操作 | 結果 |
|---|---|
| 真偽 | 要素が1つ以上あれば真、空なら偽 |
GETTYPE / GETTYPEEX |
5 |
文字列化(TOSTR や文字列との連結) |
キー=値 を , でつないだもの。例 a=1,b=x |
| 数値化 | 0 |
h1 == h2 |
要素数、キー、値がすべて一致すれば真。値が入れ子なら中身まで比べる |
ハッシュとハッシュ以外の == |
常に偽(文字列化した結果が同じでも偽) |
+(相手がスカラーかハッシュ) |
両方を文字列にして連結する |
+(相手が配列) |
配列の要素ごとに、ハッシュと文字列として連結する |
- * / % |
警告 W0024 を出す(下記) |
_h = IHASH("a", 1)
_h + 1 // "a=11"
'z' + _h // "za=1"
_h + _h // "a=1a=1"
(1,2) + _h // ("1a=1","2a=1")
- * / %(複合代入を含む)の両辺のどちらかがハッシュのときは、警告 W0024 を出す。結果は、相手がスカラーなら右辺がそのまま返り(h - 1 は 1、1 * h は h)、相手が配列なら要素ごとに計算される。意味のある結果にはならないので使わないこと。なお、配列の要素がハッシュの場合((h, 1) - 1)は W0024 は出ない。
関数の引数と , 演算子¶
汎用配列は引数や , 演算子で展開されるが、ハッシュは展開されず、そのまま1つの要素になる。
_a = (0, _h, 2) // 要素数 3。_a[1] はハッシュ
func(_h) // func の中で _argv[0] がハッシュになる
foreach¶
ハッシュも foreach で回せる。1変数の形では、値がキーの順に入る。
_h = IHASH("a", 1, "b", 2)
foreach _h ; _v
{
// _v = 1, 2
}
変数を2つ書くと、1つ目にキー、2つ目に値が入る。この形は配列と簡易配列でも使え、1つ目には 0 から始まるインデックスが入る。
foreach _h ; _k, _v { _s += _k + '=' + _v + ' ' } // "a=1 b=2 "
foreach ("p", "q") ; _i, _v { ... } // _i = 0, 1
foreach "x,y" ; _i, _v { ... } // 簡易配列も同じ
詳細は フロー制御 を参照。
値の入れ子¶
配列の要素、ハッシュの値、ハッシュのキーに、配列やハッシュを入れられる。
_h = IHASH()
_h["list"] = (1, 2, 3) // ハッシュの値に配列
_h["sub"] = IHASH("x", 1) // ハッシュの値にハッシュ
_a = (0, _h, 2) // 配列の要素にハッシュ
_a[1] = _h // 同上
_vals = HASH_VALUES(_h) // 配列の中に配列ができる
読み出しは [ ] を続けて書く。
_h["sub"]["x"] // 1
_h["list"][1] // 2
_a[1]["sub"]["x"] // 1
汎用配列の中に配列を直接入れる手段は無い。, 演算子も _a[1] = (8,9) も、配列を展開して差し込む(500 系と同じ)。
_a = (1, 2)
_a[1] = (8, 9) // 1,8,9
値のコピー¶
代入や引数渡しは値のコピーになる。コピー元とコピー先は互いに影響しない。
_h = IHASH("a", 1)
_h["self"] = _h
_h["self"]["a"] = 2
_h["a"] // 1 のまま
多次元代入¶
要素の要素へ直接代入できる。= のほか += ,= などすべての代入演算子で使える。
_h["sub"]["x"] = 5
_h["list"][0] += 10
_a[1]["sub"]["y"] = "new"
- 途中の要素が文字列なら簡易配列として書き換える。例:
_a[0]が"p,q"のとき、_a[0][1] = 'Q'で_a[0]は"p,Q"になる - 途中の要素が無いときは、空文字列を簡易配列として書き換えることになる。ハッシュは自動では作られない。例: 空のハッシュに
_h["none"]["x"] = 5とすると、_h["none"]は文字列"5"になる - 代入の根元は変数でなければならない。
(式)[0] = 1などはエラー E0029 - フィードバック演算子(参照渡し)でも要素の要素を渡せる(Tc600-4以降)。
func(&_h["sub"]["x"])の中で_argv[0]を書き換えると_h["sub"]["x"]が変わる。Tc600-3 では手前の次元が無視され、_h["x"]に書き込まれていた
制限¶
- 文字列化(
TOSTR、LOGGINGなど)した入れ子は、内側もそのまま,や=で展開されるので区切りがあいまいになる。元に戻せる形が必要なときはセーブ形式(SAVEVAR)を使う - キーに配列やハッシュを持つハッシュは作れるが、
h[キー]の序数の第1要素がキーになるため、配列をキーにして引くことはできない