【问题标题】:Why doesn't scala have easier support for Equals?为什么 scala 对 Equals 没有更简单的支持?
【发布时间】:2015-10-11 09:56:01
【问题描述】:

阅读 Martin 的书,关于平等 Object equality chapter 的一章可能会注意到,在 scala 中正确实现 equals(实际上在任何其他语言中)并不是很简单。然而 scala 非常强大和敏捷,我不敢相信它不能简化一些事情。我知道 scala 会为案例类生成正确的equals,所以我想知道为什么它不能为普通类生成简化?

为了说明我的观点,我写了一个例子来说明我会如何看待它。它可能有缺陷,我不得不使用ClassTag,由于性能原因,我知道这对于equals 这样的基本事物是非常错误的(任何提示,如果没有ClassTag,我怎么能做到这一点?),但认为scala 可以为案例类生成正确的equals,我想说它应该能够为普通类生成正确的代码,让开发人员提供应该用于比较对象的Key

trait Equality[T] extends Equals {
  val ttag: ClassTag[T]
  def Key: Seq[Any]

  def canEqual(other: Any): Boolean = other match {
    case that: Equality[_] if that.ttag == ttag => true
    case _ => false
  }

  override def equals(other: Any): Boolean =
   other match {
     case that: Equality[T] => canEqual(that) && Key == that.Key
     case _ => false
   }

  override def hashCode = Key.foldLeft(1)((x, y) => 41 * x + y.hashCode)
}

那么你可以这样使用它:

class Point(val x: Int, val y: Int)(implicit val ttag: ClassTag[Point]) extends Equality[Point]{
    override def Key: Seq[Any] = Seq(x, y)
}

我不太喜欢ClassTags,所以我可能弄错了,但它似乎有效。但这不是我要问的 - 我想知道是否有任何严重的原因,为什么 scala 本身不简化实现相等检查?

【问题讨论】:

  • 可能有很多方法。像scalaz.Equal 这样的一些可以满足类型安全的需求。有些人喜欢你的简单和狭窄的使用。没有黄金标准,所以它不在图书馆里。
  • @Odomontois 我知道,但是当我读这本书时,听起来canEqual 的方法应该涵盖 99% 的情况,我大多同意这一点。我希望 scala 具有这样的默认行为,对于最后 1%,我仍然能够覆盖 equalshashCode 和现在 canEqual,所以我不明白为什么我们没有任何好的默认值行为

标签: scala


【解决方案1】:

这是一个有趣的想法,我可以从评论中看到 scalaz 有这样的东西。我不确定我是否有完整的答案,但需要考虑的一些因素是:

案例类有点独特,因为您不应该从它们继承。假设它们没有子类,canEqual 甚至不是必需的。

即使是 Scala 中的“+”也是一个函数而不是“语言特性”,这个想法有些优雅。将其作为语言功能而不是库并不一定更好(即使在 Java 中也有许多实用程序可以帮助实现 hashcode/equals)。现有的“equals”方法不是语言特性,它只是父类 Object 上的一个方法,继承自 Java。

Scala 仍然需要很好地使用 Java,这可能是从根本上改变 equals 工作方式的一个障碍。接口要求不能强加于 scala 可能想要继承的现有 Java 类。

当您考虑语法如果它是一种语言功能时可能会是什么样子时,我不确定实际上可以消除或更改什么。
例如,开发人员仍然必须指定您建议的 Key。此外,为了能够支持 canEqual 不会改变的匿名子类和 trait mix-ins,您仍然需要明确定义类标签。

如果您提供的分析可能会更有趣,从句法上讲,如果它是一种语言功能而不是帮助程序库,它可能看起来像。我可能会遗漏它的工作原理。

【讨论】:

  • 我明白了,谢谢。这个答案不是我希望听到的,但现在我明白我的问题太宽泛了,无法在 SO 上提出,而你的回答让我思考了很多事情。
【解决方案2】:

没有“适当的等于”这样的东西,因为它取决于用例。
对于简单的情况,您的建议可能有效,但在这种情况下,使用案例类也可以。问题是,虽然对于简单的 Data 类它可以工作,但对于其他情况却不是这样。例如,当有继承时——正确的做法是什么?如果班级有私人成员 - 它应该是平等的一部分吗?公共吸气剂应该是吗?当存在循环依赖时会发生什么?
案例类不能被其他案例类继承的主要原因之一是the equality

【讨论】:

    猜你喜欢
    • 2013-11-13
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    • 2015-05-16
    相关资源
    最近更新 更多