概要
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/