在Scala中,如何针对具有类型参数的类型测试“Any”对象的类型?

时间:2014-04-18 13:34:50

标签: scala pattern-matching type-erasure

我试图获得一种类型安全的方法来转换解析JSON字符串的结果。我想检查一个字段是Map [String,any]还是普通字符串。我的第一次尝试是

def test(x:Any) = {
    x match {
        case m:Map[String,Any] => ...
        ...
}

这导致“类型模式Map [String,Any]中的非变量类型参数字符串未被选中,因为它被擦除”

查看TypeTag和ClassTag的文档,我无法找到实现这一目标的好方法。以下代码不会导致警告,但我想知道为什么它会起作用。

type StringMap = Map[String,Any]
def test(x:Any) = {
    x match {
        case m:StringMap => ...
        ...
}

2 个答案:

答案 0 :(得分:5)

这是一个错误。它已在2.11中修复:

scala> type StringMap = Map[String, Any]
defined type alias StringMap

scala> (Map(4 -> true): Any) match {
     |   case m: StringMap => true
     |   case _ => false
     | }
<console>:10: warning: non-variable type argument String in type pattern scala.collection.immutable.Map[String,Any] (the underlying of StringMap) is unchecked since it is eliminated by erasure
                case m: StringMap => true
                        ^
res0: Boolean = true

它不起作用的原因是,由于擦除,你无法说出类型参数是什么。如果您想确定它是Map[String, Any]而不是其他类型的地图,则必须检查每个密钥并确保其为String

case m: Map[_,_] if m.keySet.forall(_.isInstanceOf[String]) => 
  m.asInstanceOf[Map[String,Any]]

答案 1 :(得分:0)

无法检查类型参数,但

  

我想检查一个字段是Map [String,any]还是普通字符串

很简单:

x match {
  case s: String => ...
  // you can add cases for numbers, etc. here
  case m: Map[_, _] => ... m.asInstanceOf[Map[String, Any]]
}
  

查看TypeTag和ClassTag的文档,我无法找到实现这一目标的好方法。

标记是由编译器使用静态类型信息创建的,因此在您的情况下,您只有Any的类或类型标记。