【问题标题】:Rename and Override equals method in case class案例类中的重命名和覆盖等于方法
【发布时间】:2012-07-10 15:40:10
【问题描述】:

我想定义一个名为Ext 的特征,它将现有的equals 方法重命名为equalsByAttributes,同时定义一个新的equals 方法。该特征被使用 扩展案例类。我目前的解决方案看起来有点老套:

case class A(id: Int) extends Ext

trait Ext { p: Product =>
    // new implementation
    override def equals(obj: Any) = obj match {
        case that: AnyRef => this eq that
        case _ => false
    }

    // reimplementation of old equals implementation
    def equalsByAttributes(obj: Any) = obj match {
        case that: Product =>
            if (this.getClass.isAssignableFrom(that.getClass) || that.getClass.isAssignableFrom(this.getClass))
                p.productIterator.toList == that.productIterator.toList
            else
                false
        case _ => false
    }
}

不知道有没有直接在equalsByAttributes中引用Aequals方法,这样就可以避免这个方法的重新实现?

编辑 2012-07-12

由于有一个使用super.METHOD_NAME 引用超级实现的解决方案,我认为必须有类似的语法,例如overridden.METHOD_NAME 来访问将由该特征扩展的基类/特征中的特定实现,所以我的Ext 特质看起来像这样:

trait Ext { p: Product =>
    override def equals(obj: Any) = ...

    def equalsByAttributes(obj: Any) = overridden.equals(obj)
}

【问题讨论】:

    标签: scala case-class


    【解决方案1】:

    不要更改 case 类的 equals。如果您需要这样做,请不要让您的课程成为案例课程。更改案例类方法会使代码表现出意外(即与案例类不同),这将增加维护成本,破坏假设案例类像案例类一样工作的一切,使人们的生活变得悲惨,并让很多程序员讨厌你的胆量.

    换句话说,这不值得。不要那样做。

    【讨论】:

    • 这根本不是问题,只要我不改变equals和hasCode的预期行为。我只想优化那些关于性能的方法。此外,我会自动生成隐藏的 id,我在 equals 中进行比较,而不是最多 22 个案例类参数。它只是关于运行时优化,不会破坏任何东西,也不会增加维护成本。就我而言,做这个优化绝对值得,因为我省去了很多不必要的比较。
    • 我不得不艰难地学习丹尼尔的建议。我确实学过。因此,如果/当您需要提供 equalshashCode 方法时,我在这个 StackOverflow 答案中写了一个惯用的 Scala 解决方案:stackoverflow.com/a/56509518/501113
    【解决方案2】:

    编译器不会为已经带有 equals 的案例类生成 equals(和分别为 hashCode),即继承一个或自己声明一个。在this blog entry 中阅读更多相关信息。 AFAIK 你唯一能做的就是通过使用 productIterator 提供的 productIterator 来实现结构平等,案例类扩展,就像你在 equalsByAttributes 中所做的那样。

    【讨论】:

    • 你是对的。我推理有误。我不知何故认为 case 类中的 equals 必须在类层次结构中的上一级,因此应该可以在 trait Ext 中访问。但事实并非如此。这与在 (case) 类中直接实现 equals 相同,因此此 equals 定义只能覆盖特征的 equals 定义,而不是相反,因为超类和特征不能引用子类中的实现。
    • 顺便说一句,可以使用Scala的原始定义:ScalaRunTime._equalsScalaRunTime._hashCodeScalaRunTime._toString,而不是重新实现案例类函数equalshashCodetoString
    • @StefanEndrullis 像这样:gist.github.com/2814608?下划线前缀让我有点紧张,它可能暗示了这部分语言的易变性。不过好主意:-)
    【解决方案3】:

    此代码将使用 Ext trait 中的方法实现:

    case class A(id: Int) extends Ext { 
      def someEqual(x:Any) = { 
        super[Ext].equalsByAttributes(x) 
      } 
    }
    

    这里的 super[X] 用于指代此类扩展的特征之一。这回答了你的第二个问题。

    第一个问题:

    trait Ext { p: A => def eql(x:Any) = p.equals(x) }
    

    【讨论】:

    • 我测试了你的代码。不幸的是,它并没有解决问题。如果equalsExt 中被覆盖,p.equals(x) 仍然指的是 Ext 中的 equals 实现。
    猜你喜欢
    • 1970-01-01
    • 2012-05-05
    • 2013-02-08
    • 1970-01-01
    • 2018-06-21
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    相关资源
    最近更新 更多