递归定义类型中的Scala和==方法

递归定义类型中的Scala和==方法,scala,Scala,我知道Scala中的==方法与Java中的equals方法具有相同的语义。但是,我想了解什么时候应用于递归结构的实例。 例如,考虑一组表达式: abstract class Exp abstract class BinaryExp(l:Exp, r:Exp) extends Exp case class Plus(l:Exp, r:Exp) extends BinaryExp(l,r) case class Minus(l:Exp, r:Exp) extends BinaryExp(l,r

我知道Scala中的
==
方法与Java中的equals方法具有相同的语义。但是,我想了解什么时候应用于递归结构的实例。 例如,考虑一组表达式:

abstract class Exp

abstract class BinaryExp(l:Exp, r:Exp) extends Exp

case class Plus(l:Exp, r:Exp) extends BinaryExp(l,r)

case class Minus(l:Exp, r:Exp) extends BinaryExp(l,r)

case class Mult(l:Exp, r:Exp) extends BinaryExp(l,r)

case class Div(l:Exp, r:Exp) extends BinaryExp(l,r)

case class Num(v:Int) extends Exp
然后,当我有两个
BinaryExp
实例时,比如说
obj1
obj2
,那么
obj1==obj2
是否会导致深度(递归)相等性测试?也就是说,是否保证如果
obj1==obj2
保持不变,那么
obj1
obj2
表示相同的精确表达式树


请注意,在所有类中,我都依赖于
==
的默认实现(它不会在任何地方被覆盖)。

这很容易测试您自己:

val x = Plus(Num(1), Num(2))
val y = Plus(Num(1), Num(2))
val z = Plus(Num(1), Num(3))

println(x == y) // prints true
println(x == z) // prints false
这些给出正确答案的事实表明,相等性检查正在检查子表达式的“深度”相等性

此外,您可以在中看到:

对于每个case类,Scala编译器都会生成equals方法,该方法实现结构相等

“结构平等”是一种你想知道的深度平等检查

最后,如果您真的想了解语法糖之外的情况,可以在运行
scalac
或启动REPL时使用选项
-xPrint:typer
。如果将该选项与REPL一起使用,然后声明类
Plus
,则会得到以下结果(简称):

scala>case类Plus(l:Exp,r:Exp)扩展了BinaryExp(l,r)
[[typer末尾的语法树]]//Scala源:
...
case class Plus使用ScalaObject扩展$line2.$read.$iw.$iw.BinaryExp,使用可序列化的产品{
...
override def equals(x$1:Any):Boolean=Plus.this.eq(x$1.asInstanceOf[java.lang.Object])。| |(x$1匹配){
案例(l:$line1.$read.$iw.$iw.Exp,r:$line1.$read.$iw.Exp)$line3.$read.$iw.$iw.Plus((l$1@,(r$1@)))如果l$1.==(l)和(r$1.==(r))=>x$1
大小写=>false
});
因此,在第一个
case
中,您将看到
Plus.equals
正在调用
if l$1.==(l)&&(r$1.==(r))
以检查相等性。换句话说,case类生成的相等方法调用其子表达式上的
=
,以检查它们的相等性

scala> case class Plus(l:Exp, r:Exp) extends BinaryExp(l,r)
[[syntax trees at end of typer]]// Scala source: <console>
...
case class Plus extends $line2.$read.$iw.$iw.BinaryExp with ScalaObject with Product with Serializable {
  ...
  override def equals(x$1: Any): Boolean = Plus.this.eq(x$1.asInstanceOf[java.lang.Object]).||(x$1 match {
    case (l: $line1.$read.$iw.$iw.Exp, r: $line1.$read.$iw.$iw.Exp)$line3.$read.$iw.$iw.Plus((l$1 @ _), (r$1 @ _)) if l$1.==(l).&&(r$1.==(r)) => x$1.asInstanceOf[$line3.$read.$iw.$iw.Plus].canEqual(Plus.this)
    case _ => false
  });