rubyを書いていると時たまarray.map(&:to_i)みたいな書き方を見るけど、あまり理解できてなかったのでちょっと調べてみた。
そうすると、rubyの「ブロック」だったり「Procオブジェクト」とかの理解もなかったなーと思ったのでarray.map(&:to_i)を解説しがてら「ブロック」と「Procオブジェクト」も解説する。
ブロックとは
一言で説明するなら「処理のまとまり」のこと。
メソッドは受け取ったブロックを、メソッド内でyieldを呼び出すことで実行することができる。
例えばこのように
def block_test
puts "first"
yield
puts "second"
end
block_test do
puts 'called block'
end
# "first"
# "called block"
# "second" の順に表示される
この例だと、block_test メソッドは 処理puts 'called block'をブロックとして受け取り、メソッドの中でyieldが呼ばれたら受け取ったブロックを実行する。
Procオブジェクトとは
上記で説明したブロックは「処理のまとまり」としてメソッドに渡すことはできるが、オブジェクトではないので変数に代入したりとかはできない。もし変数に代入して流用などしたい場合には、Procを使う。
簡単に説明すると、Procはブロックをオブジェクト化したものであり、変数への代入ができたりするので処理の使い回しができる。
def proc_test(&block)
puts 'first'
block.call if block
puts 'second'
end
proc_test do
puts "hello, I'm Proc"
end
# 'first'
# 'hello, I'm Proc'
# 'second' の順に表示される
まずproc_test メソッドの呼び出しだが、ここはblock.rbの例と変わらない。呼び出し時にブロックを渡している。
block.rb と異なるのはproc_test メソッドの定義で(&block)という仮引数が指定されているところである。
& を仮引数に前置することでメソッド呼び出し時に受け取ったブロックを、Procオブジェクト化して変数blockに納めている。
そして、メソッド内でProcオブジェクトを呼び出すにはblock に対して callメソッドを呼ぶと実行できる。
じゃあ、map(&:to_i)とは...?
まずよく見るmapの使い方はこのような
s_nums = ["1", "2", "3"]
nums = s_nums.map {|n| n.to_i}
puts nums
# [1, 2, 3]と表示される
じゃあmap(&:to_i)は何が行われているかと言うと、
s_nums.map(&:to_i)
シンボル化したメソッド:to_i に & を前置すると、自動的に:to_i に対してto_proc メソッドが呼び出される。そうするとto_iがProcオブジェクトとなる。
このProcオブジェクトがレシーバのs_numsの要素に繰り返し呼ばれて、新たに整数の配列を返す、と言うことが行われている。