【问题标题】:In Scala, how to test the type of an 'Any' object against a type with type parameter?在 Scala 中,如何针对具有类型参数的类型测试“任何”对象的类型?
【发布时间】:2014-06-03 00:46:17
【问题描述】:

我正在尝试一种类型安全的方式来转换解析 JSON 字符串的结果。我想检查一个字段是 Map[String, any] 还是纯字符串。我的第一次尝试是

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

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

翻阅 TypeTag 和 ClassTag 的文档,我找不到一个好的方法来完成它。以下代码不会导致警告,但我想知道它为什么会起作用。

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

【问题讨论】:

  • 编译器没有抱怨并不意味着第二种解决方案有效。使用任何一段代码,定义为 Map(1 -> 2) 的 Map 都会遇到该匹配条件,即使这不是您想要的。
  • 在一些非常低级的代码之外,使用AnyMap[String, Any] 的方法签名在精心设计的Scala 代码中几乎不存在。

标签: scala pattern-matching type-erasure


【解决方案1】:

这是一个错误。它已在 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]]

【讨论】:

    【解决方案2】:

    无法检查类型参数,但是

    我想检查一个字段是 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 的类或类型标签。

    【讨论】:

      猜你喜欢
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多