Scala 专题教程-Case Class和模式匹配(4): 模式的种类(三)

jerry Scala 2015年11月25日 收藏

类型模式
你可以使用类型模式匹配来代替类型检查和类型转换。比如:

  1. def generalSize(x:Any) = x match{
  2. case s:String => s.length
  3. case m:Map[_,_] =m.size
  4. case _ => -1
  5. }

函数generalSize返回某些对象长度或是大小。它的参数类型为Any,因此可以传入任意类型的数据。 模式 s:String 为一类型模式,匹配任意类型为String的非空对象。变量s为匹配的字符串。
第二个匹配 m:Map[_,_] 匹配任意类型的Map对象,这里我们不关心具体的key和value,因此使用通配符_,如果你需要在后面表达式中使用key,value,可以使用key,value替换掉_。

对于Map类型的数据,我们能否匹配指定Key或value类型的数据呢,比如:

  1. def isIntIntMap(x:Any) = x match {
  2. case m:Map[Int,Int]=>true
  3. case _ => false
  4. }

此时编译器会给出警告:

  1. <console>:9: warning: non-variable type argument Int in type pattern Map[Int,Int] is unchecked since it is eliminated by erasure
  2. case m:Map[Int,Int]=>true
  3. ^
  4. isIntIntMap: (x: Any)Boolean

Scala 和Java类似对于generic类采用了?type erasure?,也就是说运行时不保存Map的Key和Value的类型,因此我们无法匹配指定类型Key或Value的Map对象。
我们可以看到

  1. scala> isIntIntMap(Map(1->1))
  2. res14: Boolean = true
  3.  
  4. scala> isIntIntMap(Map("a"->"b"))
  5. res15: Boolean = true
  6.  

这两个都返回true,这个和预期不同,因此对于这种情况,编译器会给出警告,pattern Map[Int,Int]中的类型不起作用。
但有一个特例,数组和一般的generic处理不同,它支持匹配元素类型。比如:

  1. def isStringArray(x:Any) = x match{
  2. case a:Array[String]=>"yes"
  3. case _ => "no"
  4. }

测试结果如下:

  1. scala> val as =Array("abc")
  2. as: Array[String] = Array(abc)
  3.  
  4. scala> isStringArray(as)
  5. res16: String = yes
  6.  
  7. scala> val ai = Array(1,2,3)
  8. ai: Array[Int] = Array(1, 2, 3)
  9.  
  10. scala> isStringArray(ai)
  11. res17: String = no
  12.