2016-02-29 95 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 
}