これは「Ruby脳にはCrystalつらい Advent Calendar 2015」の15日目の記事です。
Ruby の String#to_i
は数字以外の文字列の場合に 0 を返します。C の atoi()
と同じです。
% ruby -e 'p "abc".to_i' 0
Crystal の String#to_i
は数字以外の文字列の場合にエラーになります。
% crystal eval 'p "abc".to_i' invalid Int32: abc (ArgumentError) [4367687] *CallStack::unwind:Array(Pointer(Void)) +87 [4367578] *CallStack#initialize<CallStack>:Array(Pointer(Void)) +10 [4367530] *CallStack::new:CallStack +42 [4367423] *Exception +31 [4367357] *ArgumentError#initialize<ArgumentError, String>:CallStack +29 [4367297] *ArgumentError::new<String>:ArgumentError +97 [4365729] *String#to_i32<String, Int32, Bool, Bool, Bool, Bool>:Int32 +257 [4365456] *String#to_i<String, Int32, Bool, Bool, Bool, Bool>:Int32 +32 [4365404] *String#to_i<String>:Int32 +92 [4347097] ??? [4354112] main +32 [140343524641344] __libc_start_main +240 [4323881] _start +41 [0] ???
Ruby の String#to_i
よりは Integer()
に似ています。
% ruby -e 'p Integer("abc")' -e:1:in `Integer': invalid value for Integer(): "abc" (ArgumentError) from -e:1:in `<main>'
Crystal の気持ちはわかるような気がしますが、ちょっとつらい。
String#to_i?
というメソッドもありますが、これは 0 ではなく nil を返します。
% crystal eval 'p "abc".to_i?' nil
Ruby のようにエラーにせずに 0 を返すには、0 を返すブロックを指定します。
% crystal eval 'p "abc".to_i{0}' 0
Ruby の String#to_i
は数字で始まっていれば、後ろに数字以外の文字があってもエラーにならず、数字部分の数値を返します。
% ruby -e 'p "123abc".to_i' 123
これも Crystal ではエラーになってしまいますが、引数に strict: false
を渡すとと数字部分だけを評価します。
% crystal eval 'p "123abc".to_i(strict: false)' 123
Rubyと同じように、先頭が数字以外の場合に 0 を返して、かつ後続する数字以外の文字を無視するようにするには、to_i(strict: false){0}
とすればよいです。
% crystal eval 'p "abc".to_i(strict: false){0}' 0 % crystal eval 'p "123abc".to_i(strict: false){0}' 123