2

在 Scala 2.10.2 中

sealed abstract class A  

sealed trait Foo{
  sealed abstract class B extends A 
  final class C extends B  
  final class D extends B  
  final class E extends A  
}

object Main extends Foo{

  def bar = (new C(): A) match{
    case _: C => "c" 
    case _: D => "d"
    case _: E => "e"
  }

}

编译器说

[警告] A.scala:12:匹配可能并不详尽。
[警告] 它会在以下输入上失败:C()、D()、E()
[警告] def bar = (new C(): A) match{

Main#bar成功与回报"c"

难道我做错了什么?或者这是 scalac 错误?

https://github.com/scalaz/scalaz/issues/468

4

1 回答 1

4

不同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)
于 2013-08-11T15:32:00.390 回答