はじめに
この記事は書籍「プロを目指す人のためのRuby入門」に掲載できなかったトピックを著者自らが紹介するアドベントカレンダーの22日目です。
本文に出てくる章番号や項番号は書籍の中で使われている番号です。
今回はHash#to_proc
とMethod#to_proc
を紹介します。
必要な前提知識
「プロを目指す人のためのRuby入門」の第10章まで読み終わっていること。
Hash#to_proc と Method#to_proc
10.5.2項ではシンボルがto_proc
メソッドを持つことを説明しました。to_proc
メソッドを持つオブジェクトは他にも存在します。ここではハッシュのto_proc
メソッドとMethodクラスのto_proc
メソッドを紹介します。
ハッシュの場合
Ruby 2.3からはハッシュもto_proc
メソッドを持つようになりました。ハッシュをProcオブジェクトに変換すると、実行時に第1引数に渡された値が元のハッシュのキーに一致した場合にハッシュの値を返します。一致するものがなければnil
が返ります。
hash = { japan: 'yen', us: 'dollar', india: 'rupee' }
# to_procを使わない場合
without_to_proc = proc { |key| hash[key] }
without_to_proc.call(:japan)
#=> "yen"
without_to_proc.call(:italy)
#=> nil
# to_procを使う場合
with_to_proc = hash.to_proc
with_to_proc.call(:japan)
#=> "yen"
with_to_proc.call(:italy)
#=> nil
これにより、キーの配列からハッシュの値をマッピングしたりする際に簡潔に書けるようになります。
hash = { japan: 'yen', us: 'dollar', india: 'rupee' }
[:japan, :india, :italy].map { |country| hash[country] }
#=> ["yen", "rupee", nil]
[:japan, :india, :italy].map(&hash)
#=> ["yen", "rupee", nil]
ちなみに、上のコードはvalues_at
メソッドを使っても同じ結果が得られます。(ただし、メソッドのレシーバがキーの配列ではなく、ハッシュになります。)
hash.values_at(:japan, :india, :italy)
#=> ["yen", "rupee", nil]
Methodオブジェクトの場合
Rubyではメソッドの定義についてもMethodオブジェクトという形でオブジェクト化することができます。たとえば以下はshuffle
というメソッドを定義し、それをMethodオブジェクトとして取得するコード例です。
def shuffle(str)
str.chars.shuffle.join
end
method_shuffle = self.method(:shuffle)
#=> #<Method: Object#shuffle>
Methodオブジェクトもto_proc
メソッドでProcオブジェクトに変換することができます。実行時の引数はそのまま元のメソッドの引数になり、元のメソッドが実行されます。
proc_shuffle = method_shuffle.to_proc
proc_shuffle.call('Ruby')
#=> "bRyu"
これを利用すると、&
とMethodオブジェクトを組み合わせてブロックを利用するメソッドの引数にすることも可能です。
def shuffle(str)
str.chars.shuffle.join
end
# ブロックの中で普通にメソッドを呼び出す場合
['Ruby', 'Java', 'Perl'].map { |name| shuffle(name) }
#=> ["uybR", "Jvaa", "elrP"]
# &とMethodオブジェクトを使う場合
['Ruby', 'Java', 'Perl'].map(&method(:shuffle))
#=> ["ybRu", "aJva", "Prle"]
コードとしては少しトリッキーなので、日常的に使うことはあまりおすすめできませんが、Procオブジェクトの面白い利用例の1つと言えそうです。
次回予告
次回はProcのカリー化について説明します。