我报告的一个功能听起来很奇怪,并且无法在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)
我的第一个问题是“为什么MAP [String-> Int]与MAP [INT,INT]匹配?”,它应该是与MAP[_,_]
匹配。
有趣的是,当我编辑模式匹配代码并取出从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]匹配MAP [String-> INT](我仍然想知道怎么做?)没有问题?
答案 0 :(得分: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
不依赖于其值的类型。
答案 1 :(得分:1)
由于泛型类型擦除,会出现此问题。在运行时,任何类型的Map
之间没有区别。这就是为什么模式在第一个合适的情况下匹配的原因。
要检查的简单代码段:
List[String]().isInstanceOf[List[String]] // true
List[String]().isInstanceOf[List[Integer]] // true
答案 2 :(得分:0)
这是因为类型擦除。泛型类型的使用在case子句中没有用,因为它不保留类型信息。因此MAP[String->Int]
相当于Map
。这就是MAP[String->Int]
与MAP[Int->Int]
匹配的原因。
答案 3 :(得分:0)
如果不是尝试使用模式匹配,而是使用implicits和类型类机制,那会不会更容易?
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)
}