Ruby風かつ高速と噂の言語Crystalを使ってみた
ちょっと興味を持ったので巷(?)で盛り上がっているCrystalを入れてみました.使ってみたというより触ってみた程度です.
Crystalとは
公式サイトによると,次のような特徴があるそうな.
インストール
githubからインストールページに飛べます.macだとHomebrewから以下のようにインストールができるみたいです.
brew tap manastech/crystal
brew update
brew install crystal-lang
Hello,world!
Crystalのファイル拡張子はcr
だそうです.
puts "Hello, crystal!"
実行結果
$ crystal hello.cr Hello, crystal!
crystaloコマンdでコンパイルと実行をやってくれるみたいですね.
crystal run ファイル名
でもできるそう.
また,コンパイルして実行ファイルを生成することもできます.Crystalの特徴はここですね.
$ crystal build hello.cr $ ./hello
各種文法
コメント
#
でコメントができます.
# This is a comment puts "Hello, crystal!" # => Hello, crystal!
以降rubyと同じところは飛ばしていきます
Integers・Float
精度指定ができる
Crystalには整数型がいくつかあり何も指定をしなければInt32
,Int64
,UInt64
から適当なのが選ばれるみたいです.後ろにi8, i16, i32, i64
などをつけることでそれぞれの精度で扱われます.iをuにすると符号なしとなります.
a = 2 b = 2_i16 c = 2_u64 puts a.class # => Int32 puts b.class # => Int32 puts c.class # => UInt64
Floatも同じです.
1.0_f32 # Float32 1_f32 # Float32
アンダースコア表記ができる
カンマの代わりに,変数をアンダースコアで繋げて書くことができます.見やすくなりますね.でもこんな大きな数使わないような
under_score_num = 111_222_333 puts under_score_num # => 111222333
Char & String
Char型はシングルクオート'
,String型はダブルクオート"
を使います.
'a' # char "abc" #string
なのでこういうことはできません.
puts 'Hello, crystal'
$ crystal hello.cr Syntax error in ./hello.cr:1: [1munterminated char literal, use double quotes for strings puts 'Hello, crystal!' ^
Array
rubyと違って,配列内の型が何であるかに気を使わなければなりません.
a = [1, 2, 3] b = [1, "Hello", 'w'] puts a.class # => Array(Int32) puts b.class# => Array((String | Int32 | Char)) x = [] of (Int32 | Char) y = Array.new(String)
最初に中身のある配列を与えた場合はcrystalで勝手に型を与えてくれますが,配列の初期化を行う際には型の宣言が必要です.
x = [] of (Int32) x << "hello" # => no overload matches 'Array(Int32)#<<' with types String
Tuple
Tuple型があります.pythonとかを使っている人には馴染みのものですね.
tuple = {1, "hello", 'x'} puts tuple # => {1, "hello", 'x'} puts tuple.class # => {Int32, String, Char} puts tuple[1] # => hello
実行速度
とまあ簡単なところを比較してみたところで,実行速度についても比較してみました.
rubyとcrystalで単にループを回しただけです.もっといい比較方法はあるよなきっと・・・.
プログラムはこんな感じ.rubyもほぼ同じような感じです.違うのは時間を呼び出すメソッドくらい.
# 比較用プログラム start_at = Time.now.to_i * 1000 + Time.now.millisecond n = ARGV[0].to_i x = 0 y = 0 n.times do |i| x += 1 y -= 1 end end_at = Time.now.to_i * 1000 + Time.now.millisecond puts x puts y puts "crystal" + "-" * 23 puts "loop: #{n}" puts "Time:#{end_at - start_at}" puts "-" * 30
実行結果
ループ回数 | ruby実行時間(msec) | crystal実行時間(msec) |
---|---|---|
100000 | 7 | 1 |
1000000 | 77 | 3 |
10000000 | 810 | 27 |
100000000 | 8102 | 349 |
速いですね. ちなみにこれは純粋にループの前後の時間のため,コンパイルの時間などを考慮してはいないです.
それと,余談ですがCrystalではコマンドライン引数は--
の後に書きます.こんな感じ.
crystal loop.cr -- 10000000
もっと色々利点や特徴があるのでしょうが,パッと比較できるのはこの程度.もう少し触ってみようかなあ.
追実験
もうちょっとましなコード?でやろうと思ってフィボナッチ数でもやってみました.コードと実験結果です.
# フィボナッチ数を求めるプログラム def fibonacci(n) if n == 0 return 0 elsif n==1 return 1 else return fibonacci(n-1) + fibonacci(n-2) end end n = ARGV[0].to_i start_at = Time.now.to_i * 1000 + Time.now.millisecond fibonacci(n) end_at = Time.now.to_i * 1000 + Time.now.millisecond puts "crystal" + "-" * 23 puts "number: #{n}" puts "Time:#{end_at - start_at}" puts "-" * 30
n番目 | ruby実行時間(msec) | crystal実行時間(msec) |
---|---|---|
10 | 0 | 0 |
20 | 1 | 0 |
30 | 180 | 11 |
40 | 26267 | 1327 |
Written with StackEdit.