これは「Ruby脳にはCrystalつらい Advent Calendar 2015」の4日目の記事です。
昨日の記事で、Crystal は深さが不定の配列が作れなくてつらいと書いたんですが、 実際にできないわけないだろうから方法を調べて4日目の記事にしようと思ってたところ、Twitterやコメントで方法を教えてもらいました。
このアドベントカレンダーは「Crystalつらいと言ってたら詳しい人がきっと教えてくれるだろう」という下心で始めたので思惑通りです :-)
深さが不定の配列を作る場合は、型(クラス)にエイリアスを設定します。
昨日の記事にコメントしていただいた例:
alias Hoge = Int32 | String | Array(Hoge) array = [] of Hoge array.push 1 array.push "2" array.push [3, "4"] of Hoge array.push [5, "6", [7, "8", ["9", 10] of Hoge] of Hoge] of Hoge p array #=> [1, "2", [3, "4"], [5, "6", [7, "8", ["9", 10]]]]
ちゃんと深さが不定の配列が作れます!つらくない!
ちなみに深い階層に動的に追加しようとするとコンパイルエラーになります。
alias Hoge = Int32 | String | Array(Hoge) array = [] of Hoge array.push [] of Hoge array.last.push [] of Hoge Error in ./hoge.cr:4: undefined method 'push' for String (compile-time type is (String | Int32 | Array(Hoge))) array.last.push [] of Hoge ^~~~
配列の要素となりうる値は Int32, String, Array(Hoge) のいずれかで、Int32 や String には push メソッドがないためです。
つぎのようにして、型チェックをいれれば大丈夫です。
alias Hoge = Int32 | String | Array(Hoge) array = [] of Hoge array.push [] of Hoge last = array.last last.push [] of Hoge if last.is_a? Array p array #=> [[[]]]
ちょっとつらい…。
なお次のように宣言すると、CPUを100%使い続けてコンパイルが終わりません。無限ループ?
alias Hoge = Array(Int32 | String | Hoge)
つらい…。