为什么在“splatting”关键字参数时**是可选的?

时间:2016-01-14 15:59:00

标签: ruby method-invocation

鉴于此方法定义:

def foo(a = nil, b: nil)
  p a: a, b: b
end

当我使用单个哈希参数调用方法时,无论**如何,哈希都会隐式转换为关键字参数:

hash = {b: 1}
foo(hash)     #=> {:a=>nil, :b=>1}
foo(**hash)   #=> {:a=>nil, :b=>1}

我可以传递另一个(空)哈希作为解决方法:

foo(hash, {}) #=> {:a=>{:b=>1}, :b=>nil}

但是,这看起来非常麻烦和尴尬。

我原本希望Ruby更像处理数组,即:

foo(hash)     #=> {:a=>{:b=>1}, :b=>nil}
foo(**hash)   #=> {:a=>nil, :b=>1}

使用文字:

foo({b: 1})   #=> {:a=>{:b=>1}, :b=>nil}
foo(b: 1)     #=> {:a=>nil, :b=>1}
foo(**{b: 1}) #=> {:a=>nil, :b=>1}

当前的实现看起来像一个缺陷,我希望它的工作方式显而易见。

这是一个被忽视的边缘案例吗?我不这么认为。可能有一个很好的理由没有以这种方式实现。

有人可以开导我吗?

1 个答案:

答案 0 :(得分:2)

  1. 至于缺少key: value部分:

    我的猜测是,为了使方法调用变得简单,Ruby总是将**形式解释为没有大括号作为带有省略大括号的散列,无论它实际上是否会被解释为这样的散列或关键字参数

    然后,为了将其解释为关键字参数,**被隐式应用于它。

    因此,如果您已经传递了显式哈希,它将不会对上面的过程产生影响,并且可以将其解释为实际哈希或关键字参数。

    当你明确地传递method(**{key: value}) 时会发生什么:

    method(key: value)
    

    是散列的分解:

    method({key: value})
    

    然后被解释为带有省略大括号的哈希:

    =filter(A:A; B:B=max(B:B))
    

    然后被解释为哈希或关键字参数。

  2. 对于优先于其他参数的关键字参数,请参阅Ruby core上的这篇文章:https://bugs.ruby-lang.org/issues/11967