Ruby 2.7 の変更点 - Numbered parameter

Ruby 2.7 アドベントカレンダーの4日目の記事です(が、書いてるのは12月7日です)。

qiita.com

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 について話してたわ。大勝利では。