Ruby の String#to_i と組み込み関数の Integer() は違う
文字列から数値への変換に String.to_i
を使っていると、思わぬ問題に出くわすことがある。
整数とみなせない文字があればそこまでを変換対象とします。変換対象が 空文字列であれば 0 を返します。
このように説明されているが、これをそのまま解釈すると、以下のような挙動が予想できる。
irb(main):001:0> "10".to_i => 10
irb(main):002:0> "10fixnum".to_i => 10
irb(main):003:0> "".to_i => 0
ただ、次のような挙動は意外だった。
irb(main):001:0> " 10".to_i => 10
irb(main):002:0> "fixnum".to_i => 0
最初の例は「文字列中の先頭の空白文字は無視される」と推測できるが、次の例はどうだろうか。明らかに数値ではない文字列の場合はエラーになりそうだが、この場合、
- 先頭の文字
f
が整数とみなせない - よって空文字列が変換対象
- 変換対象が 空文字列であれば 0 を返す
という挙動らしい。
変換できない場合はエラーにする
変換できないときに 0
を返すのはコードをシンプルにできるが、バグの原因にもなりやすい。
変換できない場合はエラーにしたいところだが、Ruby の Time.parse で文字列を Time に変換するときのエラーチェックと同様、String.to_i
にはエラーを検出する仕組みがない。
どうするか、というと組み込み関数の Integer
を使う。
irb(main):001:0> Integer("10fixnum")
ArgumentError: invalid value for Integer: "10fixnum"
from (irb):7:in `Integer'
from (irb):7
from :0
リファレンスマニュアルにもあるように、変換できない場合は、例外 ArgumentError が発生する。