Scala匹配和引用相等性检查

时间:2019-09-20 09:34:43

标签: scala

取决于变量类型,Scala有时匹配值,有时不匹配。 这个简单的程序说明了这个问题:

class NotEqualToAnything {
  override def equals(obj: Any): Boolean = false
}

val x = new NotEqualToAnything()
x match {
  case `x` =>
    println("WTF x equal to itself")
  case _ =>
    println("no-match") // This got printed
}

val y: AnyRef = new NotEqualToAnything()
y match {
  case `y` =>
    println("WTF y equal to itself") // This got printed
  case _ =>
    println("no-match")

当变量的类型为AnyRef时,生成的代码包含对BoxesRunTime.equals的调用,该调用实际上在调用y == y之前进行了y.equals(y)检查。当变量的类型为NotEqualToAnything时,我们进行了两次标准的x == null检查,然后调用了x.equals(x)

我对此进行了测试

Scala 2.13.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_201).

我想知道这是否是编译器错误,是否应该报告这是否是“期望的”行为。我认为这两种情况的行为应相同。

一种假设是,编译器期望类在重写equals时遵循协定,因此期望equals具有反射性(x.equals(x) == true)。有人可以确认确实如此吗?

1 个答案:

答案 0 :(得分:5)

a contract for equalsx.equals(x)必须为真。如果您违反该合同,那么依赖它的很多事情将不再起作用。

编译器(例如收集库)必须假定对象是“行为良好的”。如果某些东西没有破坏,那不是编译器错误。

其结果是编译器可以在感觉上优化某些东西。在当前情况下,当已知静态类型不需要BoxesRunTime.equals开销时即可。