Crystal でも深さが不定の配列が作れてつらくない…?

これは「Ruby脳にはCrystalつらい Advent Calendar 2015」の4日目の記事です。

qiita.com

昨日の記事で、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)

つらい…。