2010-09-24 93 views
28

我有以下的Scala代碼。斯卡拉模式匹配混淆選項[任何]

import scala.actors.Actor 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! "Hi" 
     case i:Int => sender ! 0 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

Test.test後,我得到的輸出:

scala> Test.test 
Int received Some(Hi) 
Int received Some(0) 

我期待輸出

String received Some(Hi) 
Int received Some(0) 

有什麼解釋?

作爲第二個問題,我得到unchecked警告上述如下:

C:\scalac -unchecked a.scala 
a.scala:17: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:18: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
a.scala:22: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:23: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
four warnings found 

我怎樣才能避免警告?

編輯:謝謝你的建議。丹尼爾的想法是好的,但似乎並沒有與泛型類型的工作,如下面

def test[T] = (Alice !? (100, "Hello")) match { 
    case Some(i: Int) => println ("Int received "+i) 
    case Some(t: T) => println ("T received ") 
    case _ => 
} 

的例子以下 錯誤遇到 警告:warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

回答

36

這是因爲類型擦除。除了數組之外,JVM不知道任何類型參數。因此,Scala代碼無法檢查OptionOption[Int]還是Option[String] - 該信息已被刪除。

您可以治好你的代碼這種方式,雖然:

object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

這樣,你是不是測試的Option類型是什麼,但什麼內容類型是 - 假如有任何內容。 A None將落入默認情況。

+0

謝謝!其他答案也很好,包括Kevin提出的解決方法。但是,這似乎是修復我的代碼沒有太多重寫的最優雅的方式。 – Jus12 2010-09-24 17:13:45

+0

你能爲類屬類型提出一個類似的解決方法嗎?如: 'def test [T] =(Alice!?(100,「Hello」))match {case Some(t:T)=> println(「T received」); case _ => println(「別的東西收到」)}' – Jus12 2010-09-25 15:03:11

+1

@ Jus12這種方式是行不通的。你需要得到一個'm:Manifest [T]',然後如果m.erasure.isAssignableFrom(t.getClass())=>'做一些事情,如'Some Some(t:T)。 – 2010-09-25 20:50:29

8

有關類型參數的任何信息,只適用於編譯時間,而不是在運行時(這被稱爲類型擦除)。這意味着在運行時Option[String]Option[Int]之間沒有區別,所以類型Option[String]上的任何模式匹配也將匹配Option[Int],因爲在運行時,兩者都只是Option

由於這幾乎總是不符合您的要求,所以您會收到警告。避免警告的唯一方法不是在運行時檢查某些東西的泛型類型(這很好,因爲它無法像你想要的那樣工作)。

有沒有辦法來檢查Option是否是Option[Int]Option[String]在運行時(比如果它是一個Some檢查內容等)。

2

如前所述,你在這裏反對擦除。

對於解決方案......這是正常使用Scala的演員來定義你很可能會發送的每個信息類型的案件類別:

case class MessageTypeA(s : String) 
case class MessageTypeB(i : Int) 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! MessageTypeA("Hi") 
     case i:Int => sender ! MessageTypeB(0) 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(MessageTypeB(i)) => println ("Int received "+i) 
     case Some(MessageTypeA(s)) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(MessageTypeB(i)) => println ("Int received " + i) 
     case Some(MessageTypeA(s)) => println ("String received " + s) 
     case _ => 
    } 
    } 
}