昨日見たRubyの「なんじゃこりゃあ」な書き方
[[1,2], [5,3], [4, 1]].sort_by(&:first)
=> [[1, 2], [4, 1], [5, 3]]
何この挙動初めて知った
— ゆうなんとか@右手治ってないです (@yuu_hara) 2013, 7月 8
普段なら
[[1,2], [5,3], [4, 1]].sort_by{|x| x.first }
と書くところのやつですが、何この記法…
何はなくともまずはドキュメント
というわけでドキュメントを確認していきましょう。メソッド呼び出しには違いないはずなので、とりあえずまずはメソッド呼び出しを確認します。
ブロックつきメソッドの呼び出し方
ブロックつきのメソッドを呼び出す方法は次の3パターンです。
method(arg1, arg2, ...) do [`|' 式 ... `|'] 式 ... end method(arg1, arg2, ...) `{' [`|' 式 ... `|'] 式 ... `}' method(arg1, arg2, ..., `&' proc_object)
上のツイートの例は3つ目のものが近そうです。となると上のhash_object
は
Procへのの暗黙的な変換
ここでSymbolからProcへの暗黙的な変換が行われているようです。SymbolクラスではインスタンスをProcへ変換するときに呼び出されるto_procが以下のように再定義されています。
to_proc -> Proc[permalink]
self に対応する Proc オブジェクトを返します。生成される Proc オブジェクトを呼びだす(Proc#call)と、 その第一引数の self という名前のメソッドを 残りの引数を渡して呼びだされます。
:to_i.to_proc["ff", 16] # => 255 (1..3).collect(&:to_s) #=> ["1", "2", "3"] (1..3).inject(&:+) #=> 6
2番めの例がまさにそれですね。
というわけで…
- ブロックをとるメソッドでは、&のあとの値は暗黙的にProcへと変換される
- ブロックに渡される引数はそのままの順番で、変換されたProcオブジェクトのProc#callに渡される
ということが判りました。