2011-09-02 57 views
11

此文件:關於這個Scala模式匹配中未經檢查的類型參數的警告?

object Test extends App { 
    val obj = List(1,2,3) : Object 
    val res = obj match { 
     case Seq(1,2,3) => "first" 
     case _ => "other" 
    } 
    println(res) 
} 

給出了這樣的警告:

Test.scala:6: warning: non variable type-argument A in type pattern Seq[A] 
is unchecked since it is eliminated by erasure 
    case Seq(1,2,3) => "first" 

斯卡拉版本2.9.0.1。

我不明白如何執行匹配需要擦除類型參數。這第一種情況子句意味着要問,如果OBJ是3個元素等於1,2序列,和3

我能明白這一點警告,如果我寫的是這樣的:

case strings : Seq[String] => ... 

爲什麼我會收到警告,以及讓它消失的好方法是什麼?

順便說一下,我確實希望與靜態類型的Object進行匹配。在真正的代碼中,我正在解析類似於Lisp數據的東西 - 它可能是字符串,基準序列,符號,數字等。

+0

在一個有趣的說明,斯卡拉版本2.8.1在這種情況下不會給出這個警告 – thoredge

+0

@thoredge,我的猜測是2.9.0中的警告可能被認爲是一種改進。我不知道這個特殊情況是否可預見。 – huynhjl

回答

5

下面是對場景背後發生的一些見解。考慮以下代碼:

class Test { 
    new Object match { case x: Seq[Int] => true } 
    new Object match { case Seq(1) => true } 
} 

如果用scalac -Xprint:12 -unchecked編譯,你會看到代碼只是擦除階段(ID 13)之前。對於第一型圖案,你會看到類似這樣的:

<synthetic> val temp1: java.lang.Object = new java.lang.Object(); 
if (temp1.isInstanceOf[Seq[Int]]()) 

對於Seq提取模式,你會看到類似這樣的:

<synthetic> val temp3: java.lang.Object = new java.lang.Object(); 
if (temp3.isInstanceOf[Seq[A]]()) { 
    <synthetic> val temp4: Seq[A] = temp3.asInstanceOf[Seq[A]](); 
    <synthetic> val temp5: Some[Seq[A]] = collection.this.Seq.unapplySeq[A](temp4); 
    // ... 
} 

在這兩種情況下,有一種類型測試以查看對象是否爲SeqSeq[Int]Seq[A])。類型參數將在擦除階段被消除。因此警告。儘管第二個可能是意想不到的,但檢查該類型是有意義的,因爲如果對象不是類型Seq該子句將不匹配,並且JVM可以繼續下一個子句。如果類型匹配,則該對象可以被轉換爲Seq,並且unapplySeq可以被調用。


RE:thoredge對類型檢查的評論。可能我們正在談論不同的事情。我只是說:

(o: Object) match { 
    case Seq(i) => println("seq " + i) 
    case Array(i) => println("array " + i) 
} 

轉化爲類似:

if (o.isInstanceOf[Seq[_]]) { // type check 
    val temp1 = o.asInstanceOf[Seq[_]] // cast 
    // verify that temp1 is of length 1 and println("seq " + temp1(0)) 
} else if (o.isInstanceOf[Array[_]]) { // type check 
    val temp1 = o.asInstanceOf[Array[_]] // cast 
    // verify that temp1 is of length 1 and println("array " + temp1(0)) 
} 

使用的類型檢查,這樣,當演員做有沒有類轉換異常。

無論警告非可變型參數A有型圖案序列[A]沒有被選中,因爲它是由擦除淘汰是合理的,是否會有情況下,有可能是類轉換異常甚至與打字檢查,我不知道。

編輯:這裏有一個例子:

object SeqSumIs10 { 
    def unapply(seq: Seq[Int]) = if (seq.sum == 10) Some(seq) else None 
} 

(Seq("a"): Object) match { 
    case SeqSumIs10(seq) => println("seq.sum is 10 " + seq) 
} 
// ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
+1

然後它是一個錯誤嗎?在這種情況下,類型檢查只是一種優化。 – thoredge

+0

@thoredge,如果沒有類型檢查,當對象不是類型爲「Seq」而不是嘗試匹配後續子句時,會得到一個* ClassCastException *。 – huynhjl

+0

如果將對象更改爲Map(1 - > 2,2 - > 3),Map(「1」 - >「2」,「2」 - >「3」),則不會得到ClassCaseException;或「」 – thoredge

4

聲明的匹配對象外至少使它消失,但我不知道爲什麼:

class App 
    object Test extends App { 
    val obj = List(1,2,3) : Object 
    val MatchMe = Seq(1,2,3) 
    val res = obj match { 
    case MatchMe => "first" 
    case _ => "other" 
    } 
    println(res) 
} 
+2

很好找。這是因爲在這種情況下,它使用*穩定的標識符模式*,而那些編譯只是爲了平等測試(按照語言規範),不需要投射。如果你想綁定變量,但你運氣不好。 – huynhjl

+0

很高興知道,但是,我需要綁定變量。 –

+1

如果我匹配類型(比如'Seq [Int]')並且任何整數序列被認爲是有效匹配(不只是(1 2,3)),該怎麼辦? – Ivan