13

我最近偶然在這個post,其中「介紹」爲Scala集合的collect方法。用法是直截了當:使用收集的地圖,斯卡拉

scala> val ints = List(1, "2", 3) collect { case i: Int => i } 
ints: List[Int] = List(1, 3) 

現在地圖基本上都是鍵值對,這是由Scala中的元組代表的名單。所以,你可能想嘗試這樣的事:

scala> val pairs = Map(1 -> "I", "II" -> 2) 
pairs: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2) 

scala> val intsToStrings = pairs collect { case pair: (Int, String) => pair } 

編譯器當然抱怨由於JVM的類型擦除模式,所以我們嘗試的第一件事就是使用存在類型:

scala> val intsToStrings = pairs collect { case pair: (_, _) => pair } 
intsToString: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2) 

雖然代碼通過了編譯器,結果是「正確的」(我們希望pair =>我們得到了對),但我們仍然沒有得到我們想要的東西。第二次嘗試是這樣的:

scala> val intsToStrings = pairs collect { 
    | case pair: (_, _) if pair._1.isInstanceOf[Int] && pair._2.isInstanceOf[String] => pair 
    | } 
intsToStrings: scala.collection.immutable.Map[Any,Any] = Map(1 -> I) 

好了,我們幾乎沒有:

scala> val realIntsToRealStrings = intsToStrings map { 
    | pair => (pair._1.asInstanceOf[Int], pair._2.asInstanceOf[String]) 
    | } 
realIntsToRealStrings: scala.collection.immutable.Map[Int,String] = Map(1 -> I) 

我們做到了,但不是從(Any,Any)只鑄造(Int,String)我們實際複製每一對,從而創造了一個新對。

現在問題來了一部分。正如我所提到的「編譯器抱怨當然......」我聽起來像是我真的知道我在說什麼。我不!我所知道的是,Java從一開始就沒有泛型。在某些時候,泛型進入了Java但不進入JVM。因此,編譯器會檢查所有類型,但只要代碼運行,JVM就不會關心參數類型。它只能看到它是一個MapList但並不表明它是一個Map[String, Int]List[Int]

所以這是我的問題。

與所有的檢查,鑄件和映射,我們成功地轉移到Map[Any,Any]Map[String,Int]。有沒有更好的方法來做到這一點?我的意思是類型有,JVM只是沒有看到他們(據我所關注的)...

回答

21
pairs collect { case p @ (_: Int, _: String) => p.asInstanceOf[(Int, String)] } 

或更簡潔,但也有一些開銷,我認爲

pairs collect { case (x: Int, y: String) => (x, y) } 
+2

酷THX !我知道Scala是足夠真棒做到這一點;) – agilesteel

+2

哦喜悅!新的特殊字符(@),我幾乎猜到了。 – Ciantic