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
の要素に繰り返し呼ばれて、新たに整数の配列を返す、と言うことが行われている。