【问题标题】:Ruby splat operator: Array(1..10).equal? [*Array(1..10)] => false?Ruby splat 运算符:Array(1..10).equal? [*Array(1..10)] => 假?
【发布时间】:2023-03-05 14:30:01
【问题描述】:

我在看:

hash_1 = Hash[*[Array("a".."j"), Array(1..10)].transpose.flatten]

所以我想,带或不带 splat 的返回“*”看起来是一样的 - 那为什么

hash_1 = Hash[[Array("a".."j"), Array(1..10)].transpose.flatten] 返回{} ?

因此当我测试时 Array(1..10).equal? [*Array(1..10)] => 错误

这样

Hash[Array(1..10)] => {}

Hash[*Array(1..10)] => {1=>2, 3=>4, 5=>6, 7=>8, 9=>10}

请帮忙。

【问题讨论】:

  • Array(1..10) == [*Array(1..10)]true 所以不清楚为什么.equal? 会返回相反的东西。
  • 是的,是的!这个我也看不懂! == 返回 true.equal? 返回 false
  • 这可能是 Ruby 中的一个错误。 equal? 应该是 == 的别名。请记住,.equal? 几乎从未使用过。 == 是正常的方法。
  • @tadman 我相信你弄错了:ruby-doc.org/core-2.4.0/Object.html#method-i-eql-3F 说“与 == 不同,equal? 方法不应该被子类覆盖,因为它用于确定对象身份(即 a.相等?(b) 当且仅当 a 与 b) 是同一个对象”。通过在[] 内展开数组,创建了一个新的Array 对象。两者匹配==,但不匹配equal?
  • @pjs 啊,谢谢你的澄清。 Ruby 有 =====eql?equal?,只是为了让你保持警觉。

标签: arrays ruby splat


【解决方案1】:

您的代码,或者更确切地说是您的探索性测试,还有另一个问题,到目前为止其他答案中没有提到:

BasicObject#equal? 当且仅当参数与接收者是相同的对象时为真。不是“具有相同值的对象”,也不是“具有相同表示的对象”,只有当它是完全相同的对象。换句话说,要使equal? 为真,只涉及一个对象,它是两个 接收者 参数。在您的情况下,有 两个 对象(即使它们具有相同的值和相同的表示),因此 equal? 可以永远返回 true。

您不应使用equal?。对象可以模拟其他对象是面向对象编程的基本原则之一(实际上,OO 是在一种语言中发明用于模拟的),但是equal? 允许您区分真实的对象及其模拟,因此它破坏了 OO。我再说一遍:测试引用相等性会使您的代码非 OO。坦率地说,在“真正的”面向对象语言中它甚至都不可能实现,而 Ruby 拥有它让我感到难过(虽然 Java 更糟糕,但在 Java 中它甚至是 默认 相等行为)。

您应该(几乎)始终使用==,这是语义值相等。在极少数情况下,您可以使用eql?(严格值相等)。在 Ruby 核心库和标准库本身中,eql? 仅与 hash 一起用于类似哈希和集合的行为。 (事实上​​,我能想到的三个地方,eql? 用在 Ruby 中,是HashSet(和SortedSet),以及类似集合的数组操作(Array#uniq,@ 987654329@、Array#&Array#|Array#-)。)切勿使用 equal?

注意:=== 是完全不同的野兽,与平等无关。 (对于不相等的东西使用三个等号是一个不幸的名字。)

【讨论】:

  • 非常感谢您的详细解答!我正在自学 Ruby,阅读像您这样解释清楚的答案总是很有帮助的。
【解决方案2】:

哈希[]

Hash[] 需要偶数个参数(或一个类似哈希的参数):

Hash['a','b']
# {"a"=>"b"}

但是

Hash[['a','b']]
# {}

在第二个示例中,只有一个参数:一个包含两个字符串的数组,它不回答 to_hash。根据 Ruby 版本,它会显示警告或引发ArgumentError

Hash[] 与 splat

你的例子:

Hash[*Array(1..10)]

等同于:

Hash[1,2,3,4,5,6,7,8,9,10]
# {1=>2, 3=>4, 5=>6, 7=>8, 9=>10}

这是偶数个参数,因此可以从每一对中创建一个哈希。

请注意,使用奇数个参数:

 Hash[1,2,3,4,5,6,7,8,9]
 # ArgumentError: odd number of arguments for Hash

【讨论】:

    【解决方案3】:

    Documentation for Ruby Hash's [] method 说您可以提供 1) 将用作键和值的值对,2) 子数组形式的键值对数组,或 3) 可转换为哈希的对象.带有 splat 的 Hash[*Array(1..10)] 与第一种情况匹配,irb 中的快速实验将显示:

    irb(main):001:0> Hash.new([1,2])
    => {}
    

    它产生一个Hash,默认值为[1,2],但不包含任何元素。当您使用 Hash[Array(1..10)] 时,这就是作为可散列对象传递的内容,即没有 splat。

    从 Ruby 2.4 开始,您会收到以下警告:

    irb(main):002:0> Hash[[1,2]]
    (irb):2: warning: wrong element type Integer at 0 (expected array)
    (irb):2: warning: ignoring wrong elements is deprecated, remove them explicitly
    (irb):2: warning: this causes ArgumentError in the next release
    (irb):2: warning: wrong element type Integer at 1 (expected array)
    (irb):2: warning: ignoring wrong elements is deprecated, remove them explicitly
    (irb):2: warning: this causes ArgumentError in the next release
    

    【讨论】:

    • 您使用的是Hash Kernel 方法,问题中未提及。
    • 是的,但是Hash()Hash[] 是不同的方法。
    • 感谢您的回答(和耐心)!但我不明白
    • @EricDuminil 你说得对,我本来打算使用.new。这些天在太多语言之间切换......我现在已经清理了它,我相信。感谢您的反馈。
    • @ayuspark 我犯了一个错误,我相信我现在已经清理了,看看修改后的答案是否更容易理解。
    猜你喜欢
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 2020-04-12
    • 2013-08-20
    • 2011-12-01
    • 1970-01-01
    相关资源
    最近更新 更多