Techioz Blog

(*) シグネチャを持つ Ruby メソッド

概要

パターン マッチングに関するこの興味深いブログ投稿には、(*) のメソッド シグネチャを持つコードがいくつかあります。

class Request < Data.define(:path, :scheme, :format)
  def deconstruct_keys(*)
    { path: @path, scheme: @scheme, format: @format }
  end

  def deconstruct(*)
    path.split("/").compact
  end
end

これは違う

def a_method(*args)

Ruby のドキュメントには情報が見つかりませんでした。

def deconstruct_keys(*) とはどういう意味ですか?

注: この質問は Ruby Weekly で言及されました。

解決策

def a_method(*args)
  ...
end

通常、これを記述すると、args 変数に格納されているメソッドのすべての引数のリストが取得されます。

def a_method(*)
  ...
end

これは同じ匿名形式です。任意の数の引数を受け入れますが、そのリスト変数に名前を付けたくありません。ここでは引数のリストに名前を付けていませんが、それを別の引数リストに分割することはできます。したがって、これは合法ではありませんが、

def a_method(*)
  # Should've just named it in the first place :(
  args = *
  ...
end

一方、これは

def a_method(*)
  another_method(*)
end

そして引数をanother_methodに渡します。それは以下と同等です

def a_method(*args)
  another_method(*args)
end

Ruby 3 のキーワード引数でも同じことができます

def a_method(**)
  another_method(**)
end

すべての引数を転送することが目的の場合は、省略記号構文を使用する必要があることに注意してください。

def a_method(...)
  another_method(...)
end

単独の * は、キーワード引数を委任するときにおかしな動作をします。例えば、

def foo(*args, **kwargs)
  p args
  p kwargs
end

def bar(*)
  foo(*)
end

foo(1, a: 1) # Prints [1] then {:a=>1}
bar(1, a: 1) # Prints [1, {:a=>1}], then {}

foo を直接呼び出す場合、名前付き引数の構文は **kwargs に渡されますが、bar を介して委任する場合は、ハッシュに変換されてから args に渡されます。その上、 はブロック引数も転送しませんが、 … は「位置引数、名前付き引数、およびブロック引数をすべて転送する」という汎用のキャッチオールです。