概要
Rubyで書かれたコードを見ていると度々array.map(&:メソッド名)
の形式のイディオムを見かけると思います。そこで、array.map(&:メソッド名)
がどのような動きをし、またなぜそのような動きをするのかまとめました。
何をする?
簡単にいうと以下のように配列の要素1つ1つに(&:メソッド名)
で与えられたメソッドを呼んでいます。
(以下の例では文字列のa
とb
に対してString#upcase
メソッドを呼んでいます。
['a' ,'b'].map(&:upcase) #=> ["A", "B"]
なぜこのような結果になる?
引数にある&
まず、Rubyが引数内で&
を見つけるとその値をプロック(proc)
として扱おうとし、その値(この場合:upcase
)に対してto_proc
メソッドを呼びます。
class Symbol
def to_proc
puts "to_procが呼ばれました!"
end
end
p [].map(&:upcase) #=> to_procが呼ばれました!
## その後TypeErrorが発生。
Symbol#to_proc
メソッドとは?
to_proc
メソッドはその名の通り、渡されたシンボルを手続きオブジェクトのproc
として返すものです。
prc = :upcase.to_proc
p prc #=> #<Proc:0x00007f99d303e458(&:upcase)>
作成したprc
を文字列に呼んでみます。
p prc.call("string") #=> STRING
まとめると以下の事を行なっています。
:upcase.to_proc.call("string")#=> STRING
結論
つまり、array.map(&:メソッド名)
の(&:メソッド名)
部分は:メソッド名.to_proc.call
を省略した形という事になります。
以下の例で実際に両者の比較をみてみます。
# array.map(&:メソッド名)の記法
['a','b'].map(&:upcase) #=> ["A", "B"]
# 省略しない記法
['a','b'].map do |string|
:upcase.to_proc.call(string)
end
#=> ["A", "B"]
参考
Understanding Ruby's idiom: array.map(&:method)
https://therealadam.com/2008/05/01/beautiful-multi-line-blocks-in-ruby/