2016-05-13 82 views
1

上午報告了一個聽起來很奇怪並且無法用scala中的模式匹配來推理以下行爲的功能。斯卡拉+模式匹配+字符串自動裝箱

def typesPattern(x:Any)= x match{ 
    case s:String⇒ s.length 
    case n:Map[Int,Int]⇒println("Map[Int,Int]");var a = n.iterator.next();println(a._1);println(a._2);n.size;  
    case n:Map[a,b]⇒println("Map[a,b]");n.size;  
    case m:Map[_,_]⇒ m.size 
    case _ ⇒ -1 

    } 
} 

當調用上文以下println(typesPattern(Map("a"→10)))我得到以下錯誤Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101) at scala.Tuple2._1$mcI$sp(Tuple2.scala:20)

功能

第一個問題我已經是「WHY MAP [與字符串> INT]是越來越與MAP匹配[INT, INT]?「,它應該與MAP[_,_]更匹配。

有趣的是,當我編輯模式匹配代碼,並採取了從地圖和打印鍵和值的對提取的元組的碼

`def typesPattern(x:Any)= x match{ 
     case s:String⇒ s.length 
     case n:Map[Int,Int]⇒println("Map[Int,Int]");n.size;  
     case n:Map[a,b]⇒println("Map[a,b]");n.size;  
     case m:Map[_,_]⇒ m.size 
     case _ ⇒ -1 

     } 
    }` 

現在相同的調用等更早println(typesPattern(Map("a"→10)))確實匹配MAP [INT,INT]沒有問題並打印尺寸。

Map[Int,Int] 
    1 

第二個問題 「所以,這一次Scala是能夠在不使用的問題MAP [INT-> INT](我仍然不知道怎麼樣?)比賽地圖[與字符串> INT]

回答

1

發生此問題,因爲泛型類型擦除在運行時有任何類型的Map沒有區別這就是爲什麼圖中在第一個合適的情況下匹配

簡單的片段,以檢查它:。

List[String]().isInstanceOf[List[String]] // true 
List[String]().isInstanceOf[List[Integer]] // true 
+0

我錯過了。它的確回答我的問題,謝謝你的迴應。 – Gurupraveen

0

這是因爲擦除類型。使用泛型類型在case子句中是沒有用的,因爲它不保留類型信息。所以MAP[String->Int]相當於Map。這就是爲什麼MAP[String->Int]匹配MAP[Int->Int]

2

你可能試過看編譯器給你的警告嗎?

<console>:12: warning: non-variable type argument Int in type pattern scala.collection.immutable.Map[Int,Int] (the underlying of Map[Int,Int]) is unchecked since it is eliminated by erasure 
     case n:Map[Int,Int]⇒println("Map[Int,Int]");var a = n.iterator.next();println(a._1);println(a._2);n.size; 
      ^
<console>:13: warning: unreachable code 
     case n:Map[a,b]⇒println("Map[a,b]");n.size; 

事實上,這兩個行:

case n:Map[a,b]⇒println("Map[a,b]");n.size;  
    case m:Map[_,_]⇒ m.size 

無法訪問,因爲匹配在地圖上所有的三行是等價的,至少他們的模式將匹配同樣的事情。

在運行時沒有通用類型,它們被擦除,所以Map[A, B]只是一個Map。所以,你的地圖匹配唯一情況是第一位的,因爲他們是爲了

case n:Map[Int,Int]⇒println("Map[Int,Int]");var a = n.iterator.next();println(a._1);println(a._2);n.size;  

測試你得到了ClassCastException只有當您嘗試使用對待他們像一個Int值,因爲他們得到,如果你只投嘗試使用它們。檢查size不依賴於其值的類型。

0

如果不是試圖使用模式匹配,而是使用相反的含義和類型類機制,會不會容易得多?

trait TypePattern[A,B] { 
    def pattern(a: A):B 
} 

implicit object stringPattern extends TypePattern[String,Int] { 
    override def pattern(a: String): Int = a.length 
} 

implicit object mapIntIntPattern extends TypePattern[Map[Int, Int],Int] { 
    override def pattern(n: Map[Int, Int]): Int = { 
    println("Map[Int,Int]") 
    var a = n.iterator.next() 
    println(a._1) 
    println(a._2) 
    n.size 
    } 
} 

implicit object mapAnyPattern extends TypePattern[Map[Any, Any],Int] { 
    override def pattern(a: Map[Any, Any]): Int = { 
    println("Map[a,b]") 
    a.size 
    } 
} 

def pattern[A,B](x: A)(implicit typePattern: TypePattern[A,B]): B = { 
    typePattern.pattern(x) 
}