【问题标题】:Why doesn't Array's == function return true for Array(1,2) == Array(1,2)?为什么 Array 的 == 函数不为 Array(1,2) == Array(1,2) 返回 true?
【发布时间】:2010-09-17 17:53:48
【问题描述】:

Programming in Scala 中,作者写道,Scala 的== 函数比较值相等而不是引用相等。

这在列表上按预期工作:

scala> List(1,2) == List(1,2)
res0: Boolean = true

但它不适用于数组:

scala> Array(1,2) == Array(1,2)
res1: Boolean = false

作者建议改用sameElements 函数:

scala> Array(1,2).sameElements(Array(1,2))
res2: Boolean = true

他们写道:

虽然这可能看起来不一致,但鼓励对两个可变数据结构的相等性进行显式测试对于语言设计者来说是一种保守的方法。从长远来看,它应该可以帮助您避免条件语句中出现意外结果。

  1. 这是什么意思?他们在谈论什么样的意想不到的结果?如果数组在相同位置包含相同元素,除了返回 true 之外,我还能从数组比较中得到什么?为什么 equals 函数在 List 上有效,而在 Array 上无效?

  2. 如何使 equals 函数在数组上工作?

【问题讨论】:

  • 我在这本书中也注意到了这个解释。这是不正确的,请参阅下面我自己的答案。除了这个错误,这本书很好。
  • 可以简要说明发生了什么,“Java 将数组上的值相等定义为引用相等,而不是逐元素相等。”

标签: scala


【解决方案1】:

的确,书中提供的解释是有问题的,但公平地说,当他们写的时候更可信。在 2.8 中仍然如此,但我们必须改进不同的推理,因为正如您所注意到的,所有其他集合都会进行元素比较,即使它们是可变的。

为了让 Arrays 看起来像其他集合一样,已经流了很多血,但这是一个漏洞百出的抽象,最终这是不可能的。我认为正确地确定了我们应该走另一个极端,按照它们的方式提供原生数组,使用隐式机制来增强它们的能力。最明显的失败是 toString 和 equals,因为它们在数组上的行为都不是合理的,但是我们不能通过隐式转换拦截这些调用,因为它们是在 java.lang.Object 上定义的。 (只有当表达式不进行类型检查时才会发生转换,并且总是进行类型检查。)

所以你可以选择你的解释,但最终底层架构对数组的处理方式从根本上不同,如果不付出代价,就无法掩盖这一点。这不是一个可怕的情况,但这是你必须注意的事情。

【讨论】:

  • 所以你是说语言设计者不认为这种不一致是非常好的设计,而是认为这是最不痛苦的妥协?
  • 对我自己来说,编程只是“最不痛苦的妥协”,但这并不是说这会阻止我享受它。就世界其他地方而言,我想说你的释义是一个公平的总结。
【解决方案2】:

这个确切的问题已被多次提出(我自己也曾多次提出,请参阅Strange behaviour of the Array type)。

请注意,只有Array 集合不支持==,所有其他集合都支持。根本原因是Array 是Java array

【讨论】:

  • 为什么语言设计者选择 Java array 作为默认的 Array 而不是 ArraySeqWrappedArray,它们的行为会符合预期?
  • @Stefan - 因为其他人必须装箱原始类型,因此运行速度不快——这正是您想要使用数组的时候。此外,当使用 Java 代码时,很多人都会这样做,数组比比皆是。因此,较小的弊端是使Array 成为Java 数组;代价是== 的行为不一致。此外,Array 没有明显的选择,否则。应该是ArraySeqArrayBuffer 怎么样?也许WrappedArray?每一个都有存在的正当理由,但没有一个是最明显的候选者。
  • 所以你是说 a) 这是一个性能选择 b) 我通常不应该在 Scala 中使用数组,所以它们的 equals 函数不一致并不重要?跨度>
【解决方案3】:

这一切都与参考透明度有关。这个想法是,如果两个值是==,那么你使用哪个值来做某事并不重要。如果您有两个具有相同内容的数组,那么您修改哪一个显然很重要,因此== 返回 false,除非它们是 相同的

【讨论】:

  • 这是不正确的! Scala 为除 Array 之外的所有集合实现 ==。请参阅我自己的答案。
  • 我想我会使用 eq 函数来比较 Scala 中的引用
  • 嗯,是的。使用 eq 方法来做到这一点。但是请记住,当您创建一个类(不是案例类)时,如果您不覆盖 equals(),则 == 将比较引用。
  • @olle:我想我一直在做太多的 Haskell?
  • 我的问题与实例化 Array 有关。为什么说“创建类”?
猜你喜欢
  • 2014-01-25
  • 1970-01-01
  • 2011-01-29
  • 2013-07-25
  • 1970-01-01
  • 2015-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多