2

我的理解是,非数组对象上的单个 splat 调用to_a然后将元素分离。并且由于nil.to_a定义为[],因此会发生以下转换:

[:foo, *nil, :bar]
# => [:foo, *nil.to_a, :bar]
# => [:foo, *[], :bar]
# => [:foo, :bar]

以此类推,我认为非散列对象上的双重 splat 调用to_h然后将键值对分开。由于nil.to_h被定义为{},我预计会发生以下转换:

{"foo" => 1, **nil, "bar" => 2}
# => {"foo" => 1, **nil.to_h, "bar" => 2}
# => {"foo" => 1, **{}, "bar" => 2}
# => {"foo" => 1, "bar" => 2}

但实际上,它引发了一个错误:no implicit conversion of nil into Hash. 为什么它会这样?

编辑我不是在问设计背后的原因。我在问我关于双 splat 的想法哪里错了。

4

2 回答 2

3

嗯,识别模式和预测事物是我们人类的超能力。然而,这并不总是正确的。这是一个例子。Ruby 在 splat 和 double splat 中并不一致。您的思维方式是“记住”的好方法,但它并不是 Ruby 在 splats 上的工作方式。

有关更多详细信息,请参阅此错误报告。在这个错误报告中,Ruby 的作者 Matz 宁愿删除能够 splat 的特性,也nil不愿在nil.

于 2015-12-07T03:41:52.443 回答
1

之所以*nil有效,是因为 splat 运算符适用于任何响应to_anil.to_a返回的内容[]**nil不起作用的原因是它nil不响应to_hash,这是to_a' 双 splat 对应物。

如果你想要这种行为,你可以猴子补丁NilClass

class NilClass
  def to_hash
    {}
  end
end

{ "foo" => 1, **nil, "bar" => 2 }
# => { "foo" => 1, "bar" => 2 }
于 2015-12-07T05:13:17.807 回答