概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: 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}]になります。