【问题标题】:Passing an empty hash through double splat in ruby [duplicate]通过 ruby​​ 中的双 splat 传递一个空哈希 [重复]
【发布时间】:2017-08-18 21:03:45
【问题描述】:

这个想法类似于你在 python 中使用装饰器所做的事情,我不知道该方法需要什么参数,所以我将 *args, **kwargs 作为一般情况传递

当我想将空哈希作为 kwargs 传递给不带参数的方法时,问题就出现了

def my_method
  'I have run correctly'
end

args = []
kwargs = {}

my_method *args, **kwargs
=> ArgumentError: wrong number of arguments (given 1, expected 0)

有趣的是,似乎只有 kwargs 变量是问题,因为:

my_method *args, **{}
=> 'I have run correctly'

如果您能建议一种方法,将方法对象作为参数实际传递给函数,那也太完美了。

【问题讨论】:

  • 方法对象是什么意思?
  • 你可以写def receive_method(m); m.call('hi'); end; q = method(:puts) #=> #<Method: Object(Kernel)#puts>; receive_method(q) #=> 'hi'。见Object#method
  • 这是一个众所周知的错误,已在 Stack Overflow 上提出并回答,并且已在 Ruby 问题跟踪器中归档。如果以后有时间,我可以挖掘参考,但如果我没记错的话,这个问题很可能是重复的。
  • 错误报告的链接在重复问题的已接受答案中。

标签: ruby function hash keyword-argument splat


【解决方案1】:

如果没有在方法定义中声明,您不能将任意数量的参数传递给 ruby​​ 方法。只传递 *args 有效,因为 *args 是空的,基本上就好像你没有向方法传递任何参数,这是 my_method 所期望的。使用kwargs,您将传递空哈希作为参数。由于该方法被声明为不带参数,因此会引发错误。

一般来说,在 ruby​​ 中执行此操作的方法是这样的:

def my_method(*args, **kwargs)
  'I have run correctly'
end

如果 ruby​​ 方法可以接受不定数量的参数或关键字参数,则它需要在方法的定义中明确。

然而,你会更频繁地看到这样的习语:

def my_method(arg, opts={})
  # do something
end

# Invoke the method like this:
# args == ['argument', 'another argument']
# opts == {opt1: 'val1', opt2: 'val2'}
my_method('some argument', opt1: 'val1', opt2: 'val2')

关于您对 my_method *args, **kwargsmy_method *args, **{} 行为不同的观察...我首先要说的是,如果您的动机首先是学习 Ruby,那么我会再次强调我的上述观点,即 kwargs 不是一个常见的在 Ruby 中使用,至少与在 Python 中使用的方式不同。

然后我会说这很奇怪。

我注意到:

[**kwargs] # => [{}]
[**{}] # => []
# And even more interesting:
[**{}.itself] # => [{}]

所以我说**kwargs 是正确的,解释器抱怨是因为您将空哈希传递给不期望任何参数的方法。但至于为什么这与**{} 不同,我不确定。我现在正在深入研究,但老实说,我目前的怀疑是,这是口译员的侥幸。没有理由仅仅因为一个两个被分配给一个变量就应该对它们进行不同的评估......

更重要的是,double splat 运算符的采用并不是非常普遍,这主要是因为对上述opts={} 成语的偏好。这也不是许多人在实践中会遇到的用例。当程序员可以(无论是 kwargs 还是 opts)只是省略参数时,他们必须显式地将空哈希传递给这样的方法。所以是的......我认为这可能是口译员的侥幸。

【讨论】:

  • 我仍然很困惑,因为如果您不将 kwargs 声明为变量,而只是传递一个 ampty 散列文字 **{},则不会传递任何参数。另外,没有办法传递方法?
  • 方法——至少是你通常在正常编码过程中定义的方法——不是 Ruby 中的第一类对象。所以你不能直接将它们传递给方法。但是,您可以为此使用blocks,这是 Ruby 的规范处理方式。
  • 是的,我正在努力解决这些问题(来自 Python,它似乎毫无用处不方便)。关于为什么 **{} 会从存在中消失的任何想法?
  • 就像我说的,它就这样消失是没有意义的。当您尝试将**kwargs 传递给my_method 时引发错误时,**kwargs 的行为正确。我真的认为**{} 的解释器与**kwargs 的行为有任何不同是侥幸。
  • 根据链接的问题,这实际上是一个错误。如果您在这一切中的目标只是学习 Ruby 约定和标准,那么我不会太担心这一点。直接将**{} 传递给一个方法是您在调试之外几乎永远不会做的事情,因为无论如何传递“无”是默认值。 Ruby 中的规则是“关键字”,至少当它们在 Python 中工作时,只是碰巧是散列的常规参数。在我上面的示例中,opt1opt2 都是 opts 参数的一部分,但是当传递给方法时,它几乎读起来就好像它们是单独的变量一样。
猜你喜欢
  • 2017-08-06
  • 2012-08-25
  • 2021-10-14
  • 2015-01-20
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 2013-11-13
相关资源
最近更新 更多