2016-02-29 82 views
2

假设Foo是一个简单的案例类,下列表达式的值是什么情况下是2奇怪模式匹配问题

Option(myFoo) match { 
    case Some(x: Foo) => 1 
    case Some(x) if x.isInstanceOf[Foo] => 2 
    case _ => 3 
} 

查看Loss of type info in servlet code查看该问题的上下文。

+0

用例可能与您链接的内容不可分离。也就是说,你可能不能在像REPL这样的单线程上下文中显示这个例子吗?不是我不相信这个相关案例。 –

回答

1

第一和第二种情况是等价的。

这里是你的功能反编译回Java(使用scala-to-java):

斯卡拉:

type Foo = String 
def test(foo:Any) = Option(foo) match { 
    case Some(x: Foo) => 1 
    case Some(x) if x.isInstanceOf[Foo] => 2 
    case _ => 3 
} 

的Java:

import scala.*; 

public final class _$$anon$1 { 
    private int test(final Object foo) { 
     boolean b = false; 
     Some<Object> some = null; 
     final Option<Object> apply = Option$.MODULE$.apply(foo); 
     if (apply instanceof Some) { 
      b = true; 
      some = (Some<Object>)apply; 
      final Object x = some.x(); 
      if (x instanceof String) { 
       return 1; 
      } 
     } 
     if (b) { 
      final Object x2 = some.x(); 
      if (x2 instanceof String) { 
       return 2; 
      } 
     } 
     return 3; 
    } 
} 

更新!

看来,模式匹配原理不同的内部类:

case class Wrapper(wrapped: String) 

def test(a:Any) = Option(a) match { 
    case Some(x:Wrapper) => x 
    case Some(x) if x.isInstanceOf[Wrapper] => x 
    case x => ??? 
} 

可生产这样的事情:

private Object test(final Object a) { 
    boolean b = false; 
    Some<Object> some = null; 
    final Option<Object> apply = Option$.MODULE$.apply(a); 
    if (apply instanceof Some) { 
     b = true; 
     some = (Some<Object>)apply; 
     final Object x = some.x(); 
     if (x instanceof _$$anon$1$Wrapper && ((_$$anon$1$Wrapper)x)._$$anon$Wrapper$$$outer() == this) { 
      return x; 
     } 
    } 
    if (b) { 
     final Object x2 = some.x(); 
     if (x2 instanceof _$$anon$1$Wrapper) { 
      return x2; 
     } 
    } 
    throw Predef$.MODULE$.$qmark$qmark$qmark(); 
} 

所以,它还会检查“外”领域,即外部类。如果你不能控制自己的环境,比如你无法保证外部类总是同一个实例,那么模式匹配可能会失败(这很让人不快发现)。

+0

感谢您的回答!这真的很奇怪 - 但这并不意味着它应该无法访问?我有一些代码,绝对匹配第二种情况。我已经在https://github.com/kardeiz/sc-issue-20160229/上提供了一个简单的例子,如果你或其他人愿意看看 –

+0

@kardeiz请检查更新。 – Aivean

+0

哇,棘手!尽管我猜测这很有道理。非常感谢您的追踪! –

-1

在x不是Foo类的实例的情况下,说任何类型但Foo类型。但是对不起,如果x.isInstanceOf [Foo]使case 1和case2是相同的情况,那么在任何情况下都不会是2。 假设你有这个代码

def f(t:Any) = Option(t) match { 
    case Some(x: Foo) => 1 
    case Some(x) if x.isInstanceOf[Foo] => 2 
    case _ => 3 
}