String#to_i の引数(基数の指定)にみる Ruby のパージング
文字列(String)を整数(Integer)へ変換することでおなじみの String#to_i メソッド。このメソッドは、引数に整数値を指定すると、その値を文字列の基数とした上で整数変換を行う。この引数と、「引数指定時に括弧を省略できる」という Ruby の仕様によって、一見分かりにくい現象が起こるようだ*1。
事例研究
いくつかの事例を見てみよう。
irb(main):001:0> "21".to_i(16) => 33
文字列 "21" が16進数であるとみなして整数変換している。当然結果は整数値の33だ。
irb(main):002:0> "21".to_i 16 => 33
上記と同じことを行っている。違うのは引数の括弧を省略していることである。
irb(main):003:0> "21".to_i +16 => 33
これは、文字列 "21" を整数値21に変換して、16を足しているのではない。+16 という整数値を to_i に引数として(括弧を省略して)与えているのである。よって、結果はまたも上記と同じである。
irb(main):004:0> "21".to_i+16 => 37 irb(main):005:0> "21".to_i + 16 => 37
そして上の2つは、これまでの例と異なり、「文字列 "21" を整数値21に変換して、16を足している」式である。
004の式では、+16 を to_i の括弧なし引数とは解釈できない。なぜなら、その解釈の場合、メソッド名と引数がくっついているという状況なわけで、そういう解釈はできないからである。
005の式では、左右の空白のおかげで + は二項演算と判断される。
irb(main):006:0> "21".to_i +16 + 1 => 35
これは、「"21".to_i +16」の結果の33に1を足しているのではない。to_i に 「+16 + 1」(の結果の17)を引数として与えているのである。ゆえに結果は "21" を17進数とみなして整数値に直した35となる。
以下の例も参考になるだろう。
irb(main):001:0> puts 1 + 2 , 4 3 4 => nil
*1:最近あった ruby-list での議論からの気づき。