概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Ruby adds support for forwarding arguments to a method, along with the leading arguments | Saeloun Blog
- 原文公開日: 2020/09/16
- 著者: Vamsi Pavan Mahesh
- サイト: Saeloun Blog | Ruby on Rails Consulting Company based in San Francisco and Boston | Saeloun Blog
日本語タイトルは内容に即したものにしました。
読みやすさのため、原文の「argument」は訳文でメソッド定義の場合は「パラメータ」、メソッド呼び出しの場合は「引数」と表記を分けました。
Ruby 3: 引数をforwardする...
記法が第2パラメータでも使えるようになった(翻訳)
Ruby 2.7で、引数をメソッドにforwardする...
というショートハンド機能が追加されました。引数のforwardについて手軽におさらいしたい方は、私たちの昨年の記事「Ruby 2.7 adds shorthand syntax for arguments forwarding」をご覧ください。
⚓ 変更前
...
記法は、以下のようにパラメータ全体をメソッドにforwardする書き方に限定されていました。
def travel(...)
by_road(...)
end
しかし、以下のように第1パラメータを別にして、第2パラメータ以降を...
でforwardしたい場合もあります。
def travel(preference, ...)
if preference == "air"
by_flight(...)
else
by_road(...)
end
end
⚓ 変更後
Ruby 3.0で、第1パラメータに加えて、第2パラメータ以降を...
でforwardできるようになりました(#3190)。
以下のコード例で理解してみましょう。
def transform(a, ...)
process(a, ...)
end
def process(a, *args, **kwargs, &block)
if block
block.call(args, kwargs)
else
[a, args, kwargs]
end
end
このコード例では、transform
メソッドにa
という位置パラメータと...
パラメータが宣言されています。
このメソッド内で呼び出しているprocess
メソッドには、transform
メソッドと同じパラメータが引数として渡されています。そしてprocess
メソッド定義のシグネチャには、a
という位置パラメータの他に、*args, **kwargs, &block
も含まれています。
ここでのポイントは、...
という記法が以下のように振る舞うことです。
- 追加引数(複数可)が
*args
に代入される - キーワード引数(複数可)が
**kwargs
に代入される - ブロックが
&block
に代入される
transform
メソッドにいくつか値を渡して、上のコードで実験してみましょう。
⚓ コード例1: 「位置引数」のみを渡す場合
transform(1) # => [1, [], {}]
この例では、transform
メソッドのa
パラメータに1
という値が引数として渡され、これがprocess
メソッドに渡されます。
process
メソッドのblock
パラメータにはブロックが渡されていないので、process
メソッドのelse
部が実行され、[a, args, kwargs]
のa
に1
という値が代入されます。
同様に、process
メソッドのargs
パラメータには追加の引数が渡されておらず、kwargs
パラメータにもキーワード引数が渡されていません。
そしてargs
のデフォルト値は[]
、kwargs
のデフォルト値は{}
です。
したがって、出力は[1, [], {}]
になります。
⚓ コード例2: 「位置引数」「追加引数」を渡す場合
transform(1, 2, 3) # => [1, [2, 3], {}]
この例のa
は位置パラメータなので、位置パラメータa
には1
が代入され、...
には2, 3
が代入されます。
2, 3
は追加引数と認識されるので、process
メソッドの追加パラメータargs
に代入されます。
したがって、出力は[1, [2,3], {}]
になります。
⚓ コード例3: 「位置引数」「追加引数」「キーワード引数」を渡す場合
transform(1, 2, 3, a:1, b: 2) # => [1, [2, 3], {:a=>1, :b=>2}]
この場合、パラメータa
には位置引数1
が代入され、args
パラメータには追加引数[2, 3]
が代入され、kwargs
パラメータにはキーワード引数{:a=>1, :b=>2}
が代入されます。
したがって、出力は[1, [2, 3], {:a=>1, :b=>2}]
となります。
⚓ コード例4: ブロックを渡す場合
transform(1, 2, 3, a:1, b: 2) { |args, kwargs| [args, kwargs] }
# => [[2, 3], {:a=>1, :b=>2}]
この場合、ブロックパラメータblock
にブロックが渡されるので、process
メソッドのif
部分が実行されることになります。
process
メソッドのif
部分では、受け取ったブロックに追加引数とキーワード引数を渡してブロックを実行し、そのblock
は渡された引数を配列にして返します。
したがって、出力は[[2, 3], {:a=>1, :b=>2}]
になります。