带有 (*) 签名的 Ruby 方法

ard*_*igh 16 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
Run Code Online (Sandbox Code Playgroud)

这不同于

def a_method(*args)
Run Code Online (Sandbox Code Playgroud)

我在Ruby 文档中找不到任何信息。

这是什么def deconstruct_keys(*)意思?

注意Ruby Weekly上提到了这个问题

Sil*_*olo 30

def a_method(*args)
  ...
end
Run Code Online (Sandbox Code Playgroud)

通常,当我们编写此代码时,我们会得到存储在变量中的所有方法参数的列表args

def a_method(*)
  ...
end
Run Code Online (Sandbox Code Playgroud)

这是相同的匿名形式。我们接受任意数量的参数,但不希望为该列表变量指定名称。现在,我们还没有给参数列表命名,但我们仍然可以将其放入另一个参数列表中。所以虽然这合法

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

另一方面,这是

def a_method(*)
  another_method(*)
end
Run Code Online (Sandbox Code Playgroud)

并将参数传递给another_method. 它相当于

def a_method(*args)
  another_method(*args)
end
Run Code Online (Sandbox Code Playgroud)

Ruby 3 关键字参数也可以完成同样的操作

def a_method(**)
  another_method(**)
end
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的目的是转发所有参数,则应使用省略号语法。

def a_method(...)
  another_method(...)
end
Run Code Online (Sandbox Code Playgroud)

*当委托关键字参数时,孤独者会表现得很有趣。例如,

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 {}
Run Code Online (Sandbox Code Playgroud)

直接调用时foo,命名参数语法会传递给**kwargs,但通过 委托时bar,它会转换为哈希值,然后传递给*args。最重要的是,*也不会转发块参数,而通用的...“向前传递所有位置、命名和块参数”是包罗万象的。


Tod*_*obs 14

用于委托、转发或忽略参数

简单来说

此语法自 Ruby 2.7 起就已存在,但在 Ruby 3.2 中获得了额外的功能和一些相关标记。简而言之,它是一个更受限制的版本...,允许您将任意数量的参数转发/委托给另一个方法,而不必像在早期版本的 Ruby 中那样先分配它们或解构它们。它还允许您忽略任何参数,这就是您的示例所做的。

更深入的解释

***、 和之间的差异...可能会令人困惑,但在发布的代码中,它只是忽略传递的所有参数,就像您手动将每个参数分配给 Throwaway 一样_,或者收集位置、关键字和块参数而不使用任何它们在方法体中。

除了节省一些输入之外,此语法还避免了转发或忽略参数时无用的参数检查和浪费的内存分配。Ruby 的内部结构已经为此进行了优化,因此本质上是这样的方法:

def deconstruct_keys(*)
  { path: @path, scheme: @scheme, format: @format }
end
Run Code Online (Sandbox Code Playgroud)

将以更节省内存的方式采用任意数量的参数,或者根本不采用任何参数。如果您只是转发或忽略此方法的参数,它还可以避免担心调用者可能会或可能不会传递什么。

在您发布的示例中,该方法的返回值是实例变量名称和值的哈希值,与可能或可能不会传递给该方法的任何参数无关。这些变量由作为祖先类的 Data 对象定义,并且这些值可能在未发布的代码中的其他位置设置。(旁注:取消设置实例变量 auto-vivify 即使nil未设置,也不会在此处引发异常。)但是,为了解释示例的目的,要点是该方法的返回值不以任何方式相关#deconstruct_keys 方法签名,因为它当前忽略任何参数。