7

==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

次に、たとえばとの2つのインスタンスがある場合、BinaryExp結果obj1obj2深いobj1 == obj2(再帰的な)同等性テストになりますか?つまり、がobj1 == obj2成立する場合、obj1およびobj2が同じ正確な式ツリーを表すことが保証されていますか?

すべてのクラスで、のデフォルトの実装に依存していることに注意してください==(どこでもオーバーライドされません)。

4

1 に答える 1

14

これは自分でテストするのは簡単です。

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

これらが正しい答えを与えるという事実は、等価性チェックが部分式の「深い」等価性をチェックしていることを示しています。

さらに、ドキュメントで次のことを確認できます。

すべてのケースクラスについて、Scalaコンパイラは構造的同等性を実装するequalsメソッドを生成します

「構造的平等」は、あなたが疑問に思っている一種の深い平等チェックです。

最後に、構文糖衣を超えて何が起こっているのかを本当に知りたい場合は、REPL-xPrint:typerを実行または開始するときにこのオプションを使用できます。scalacそのオプションをREPLで使用してからクラスを宣言すると、次Plusのようになります(短縮されます)。

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
  });

だから、最初に埋もれているのは、平等をチェックするために呼び出しcaseていることがわかります。言い換えると、ケースクラスの生成された等価メソッドは、その部分式を呼び出して、それらの等価性をチェックします。Plus.equalsif l$1.==(l).&&(r$1.==(r))==

于 2012-08-09T21:53:29.870 に答える