Ruby 2.7 アドベントカレンダーの4日目の記事です(が、書いてるのは12月7日です)。
Numbered parameter
2.6 までは、ブロックに渡される引数を受け取るためには |
で明示的に変数を宣言する必要がありました。
[5, 2, 4, 1, 3].sort { |a, b| a <=> b } #=> [1, 2, 3, 4, 5]
2.7 では宣言しなくても _1
, _2
, ... で使用することができます。
[5, 2, 4, 1, 3].sort { _1 <=> _2 } #=> [1, 2, 3, 4, 5]
候補は @1
とか it
とか色々案があったのですが、 _1
に落ち着いたようです。
いちいち名前を考えるまでもない場合に便利ですね。 あと、コードゴルフが捗るかも。
なお numbered parameter はまだ experimental なので将来変更される可能性があります。 でも使用しても warning 等は出力されません。
numbered parameter で扱えるのは9個までです。 _10
は使えません。
def hoge(*args) yield *args end hoge(1, 2, 3, 4, 5, 6, 7, 8, 9) do p [_1, _2, _3, _4, _5, _6, _7, _8, _9] end #=> [1, 2, 3, 4, 5, 6, 7, 8, 9] hoge(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) do p [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10] end #=> undefined local variable or method `_10' for main:Object (NameError)
今までは _1
はローカル変数として扱われていたので、_1
への代入等があった場合は warning が出力され、_1
はローカル変数として扱われます。
123.tap { p _1 } #=> 123 _1 = 'abc' #=> warning: `_1' is used as numbered parameter 123.tap { p _1 } #=> "abc"
入れ子で使用した場合はパース時にエラーになります。
123.tap do _1.tap do _1 end end #=> test.rb:3: numbered parameter is already used in #=> test.rb:2: outer block here
複雑な場合は横着しないでちゃんと名前つけろってことですね。
おまけ
2015年に _1
, _2
について話してたわ。大勝利では。
@yancya なんのことだかわかりませんが、
— とみたまさひろ🍣🍺 (@tmtms) 2015年8月5日
[1, 2, 3].map.with_index { _1 * _2 } #=> [0, 2, 6]
みたいなのが好みです。