3連休ということで?、erlang, elixir, scala, rustとやった。で、頭がフラフラしてきたので、ほぼrubyだというcrystalを使ってみる。
まず、インストール
brew install crystal-lang
以下、使用感をいつくか。
シェルも正規表現もOK
最近シェルスクリプトの代わりにrubyを使ったので``(シェルプログラム呼び出し)が動くか見てみる。以下のようにmyがつくファイルを列挙し、正規表現でキャッシュしてみる。
text = `find ~/proj/ -name *my*`
text.split("\n").each do |row|
if row =~ /(my.*)/
puts $1
end
end
上記は、Ruby(ruby test1.cr
)でもCrystal(crystal test1.cr
)でも全く同じに動く。合格
Rubyとは違うところ(空配列)
https://praveenatc42.wordpress.com/2016/01/09/crystal-for-rubyists/
を見るにRubyとCrystalは色々と違うらしい。例えば以下のように、型推定ができないので空配列は無理がある。
Compilation:- compiler error introduction
array = []
array << "hello" #=> CRASH in crystal
array << "hello" #=> WORKS FINE in Ruby
Solution : Specify types of value array can have upfront.
array = [] of String # In crystal
しかし[] of String
と型を追加してみれば、acc_text配列に集めていくようなコードも問題なく動く。
text = `find ~/proj/ -name *my*`
#acc_text = [] # for Ruby
acc_text = [] of String
text.split("\n").each do |row|
if row =~ /(my.*)/
acc_text << $1
end
end
puts "#{acc_text}"
また、ダミーでもなんでも、最初に要素を入れておけば(例text = ["dummy"]
)型の指定は不要である。
text = `find ~/proj/ -name *my*`
acc_text = ["dummy"]
text.split("\n").each do |row|
if row =~ /(my.*)/
acc_text << $1
end
end
acc_text.delete_at(0) # remove "dummy" from array
puts "#{acc_text}"
並行プログラム = Beyond Ruby (spawn, concurrency, channel)
これがないと最近の言語を名乗れないらしい、「spawn, concurrency, channel」にcrystalは対応している。
Rubyにはない(Rubyで試すとspawn.cr:1:in
': undefined method Channel' for main:Object (NoMethodError)
)ともちろんコンパイルエラーになる。
せっかくなので試してみる。
ch = Channel(String).new
spawn do
puts ch.receive
puts ch.receive
puts ch.receive
end
spawn do
ch.send("apple")
ch.send("orange")
end
ch.send("grape")
$ crystal spawn.cr
grape
apple
orange
#よく理解していないが動いているようだ。
が、次のようにすると
ch1 = Channel(String).new
ch2 = Channel(String).new
spawn do
puts ch1.receive
puts ch2.receive
puts ch1.receive
end
spawn do
ch1.send("apple2")
ch2.send("orange2")
end
ch1.send("grape2")
以下のように、grape2しか出てこない。。なぜ??
$ crystal spawn2.cr
grape2
わかったような。
- puts ch1.receiveのブロックに、ch1.send("grape2")は問題なし。
- puts ch2.receiveのブロックに、ch1.send("apple2")は・・・、
- 受信側は、ch2で待っているのに来たのはch1へのsend。といういうことでまだ待つ。
- 送信側は、ch1.send("apple2")の後、ch2.send("orange2")をするかと思うと、ch1を受信してくれないので、次のch2.send("orange2")には行けず。
なるほど、送信側でもブロックするのか。。
最後に
erlang, elixir, scala, rustよりは簡単だろう。ということでちょっとcrystalを使ってみたが、思ったよりいい。
- 単に高速なrubyではなく、新しい要素もあるようで思ったより良いかもしれない。asm文の挿入などもできるみたいだし。
- 確かにrubyでかけるのは嬉しい!。少なくともrustのようにうるさくないし(が正規表現でキャッチせずに$1を表示したら実行時にfaultしたのでcrystalはrustのようにはメモリ安全ではない)。mix deps.getとかiex -S mix とかやるelixirより手続きが楽。