2016-05-13 62 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) 
}