不同Foo的路径依赖C是不同的。
这可能就是它抱怨的原因。(警告中有已知的错误。)(比如这个。)
final class C extends B {
def f(c: C) = "ok" // adding this to C
}
object Test extends App {
val f = new Foo { }
Console println (X bar new f.C())
val c = new f.C
c.f(X.c) // doesn't compile
}
object X extends Foo{
val c = new C
def bar(a: A) = a match {
case _: C => "c"
case _: D => "d"
case _: E => "e"
}
}
这更好地代表了您的能力,并使警告静音:
def bar(a: A) = a match {
case _: Foo#C => "c" // instanceof Foo$C etc
case _: Foo#D => "d"
case _: Foo#E => "e"
}
更新:还有更多要说的,即我在查看不相关的 stackoverflow 时碰巧注意到的一个未解决的问题。(一个实际的,不是问答网站。)
简而言之,它试图优化从嵌套类到其封闭实例的“外部”指针,如果发生这种情况,您就不能再在匹配中包含外部实例。通常它会同时测试 instanceof 和它的外部是正确的。
进入bar
特征并移除final
会禁用优化并修复匹配。
public static java.lang.String bar(badseal.Foo, badseal.A);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=2
0: aload_1
1: astore_2
2: aload_2
3: instanceof #9 // class badseal/Foo$D
6: ifeq 26
9: aload_2
10: checkcast #9 // class badseal/Foo$D
13: invokevirtual #13 // Method badseal/Foo$D.badseal$Foo$D$$$outer:()Lbadseal/Foo;
16: aload_0
17: if_acmpne 26
20: ldc #15 // String d
如果内部类是 final 的,scalac 至少会抱怨:
badseal.scala:17: warning: The outer reference in this type test cannot be checked at run time.
case _: C => "c"
^
但是,如果匹配在对象中,则此消息的启发式方法似乎会中断,因此您再也看不到它了。
sealed abstract class A
trait Foo {
sealed abstract class B extends A
class C extends B
class D extends B
class E extends A
def bar(a: A) = a match {
case _: C => "c"
case _: D => "d"
case _: E => "e"
}
}
object X extends Foo
然后
val f1 = new Foo { }
Console println X.bar(new f1.C)
正确警告并正确抛出。
apm@mara:~/tmp$ skalac -unchecked badseal.scala ; skala badseal.Test
badseal.scala:11: warning: match may not be exhaustive.
It would fail on the following inputs: C(), D(), E()
def bar(a: A) = a match {
^
one warning found
scala.MatchError: badseal.Foo$C@756bc09d (of class badseal.Foo$C)