-
Notifications
You must be signed in to change notification settings - Fork 64
Open
Labels
Description
注意, 以下代码都以在 scala 2.10.2 jdk 1.7中编译运行为讨论前提
trait A {
case class B(i: Int)
}
class C extends A {
def !(a:Any) = a match {
case B(0) => println("never be here")
case b: B => println("never be here")
case x => println(s"Oops, received $x")
}
}
class D extends A {
new C ! B(0)
}
new D上面代码在 scala REPL 中运行, 打印输出的结果是Oops, received B(0), 问题就出来了:
为什么
case B(0)和case b: B都没有能够匹配上?
问题的答案可以从scalac -Xprint:typer的结果中找到:
class C extends AnyRef with A {
def <init>(): C = {
C.super.<init>();
()
};
def !(a: Any): Unit = a match {
case (i: Int)C.this.B(0) => scala.this.Predef.println("never be here")
case (b @ (_: C.this.B)) => scala.this.Predef.println("never be here")
case (x @ _) => scala.this.Predef.println(scala.StringContext.apply("Oops, received ", "").s(x))
}
};
class D extends AnyRef with A {
def <init>(): D = {
D.super.<init>();
()
};
new C().!(D.this.B.apply(0))
}
在new C ! B(0)中B的类型是D.this.B, 而在C.!(a: Any)的match中B的类型都是C.this.B
那么答案也就很明确了, 引用之 @hongjiang 的论断:
这个 case 类是个内部类,这点性质与java一样,它一定要存活在它的外部对象实例内,外部实例不同,它们也不同
因此, 在实际应用中, 请谨慎使用这种用法, 除非你有特别好的理由
进一步的思考: Scala 编译器是如何实现的呢?
答案在这里, 你找找看:)