1

使用 scala ClassTags 我发现当您将它与 AnyVal 对象一起使用时,classTag.runtimeClass.isInstance 无法正常工作。这是一个片段,您可以在其中对其进行测试。有什么想法可以使它适用于 AnyVal 对象吗?

import scala.reflect.ClassTag
import scala.reflect.runtime.{universe => ru}
object Test {
  def extractField[U: ru.TypeTag](json: Map[String, Any], field: String)(implicit classTag: ClassTag[U]): Option[U] = {
    json.get(field) match {
      case Some(value) =>
        if(classTag.runtimeClass.isInstance(value))
          Some(value.asInstanceOf[U])
        else {
          None
        }
      case _ =>
        None
    }
  }
  val map: Map[String,Any] = Map("k1" -> 2.0, "k2" -> "v")
  extractField[Double](map,"k1") // RETURNS NONE
  extractField[String](map,"k2") // RETURNS Some("v")
}

顺便说一句,我正在使用 Scala 2.10

4

1 回答 1

2

这是显示相同问题的更简单的代码:

val c = classTag[Double].runtimeClass
println(c) // double
println(c == classOf[Double]) // true
println(c.isInstance(0.0)) // false

isInstance需要一个Object. classOf[Double]表示 JVM 原语的“类” double(并且classTag[Double].runtimeClass是相同的)。由于对象不能是原始对象,classOf[Double].isInstance(something)因此始终为假。

Map[String, Any]实际上不包含AnyVals,而只包含对象;当你写

val map: Map[String,Any] = Map("k1" -> 2.0, "k2" -> "v")

2.0自动装箱到java.lang.Double,因此您的代码正确地告诉您Double此键下没有。但是你可以写一个简单的辅助函数(我以为它在标准库的某个地方,但不记得在哪里):

private val boxedClasses = 
  Map[Class[_], Class[_]](classOf[Double] -> classOf[java.lang.Double], ...) // the rest of AnyVal classes
def boxed(c: Class[_]) = boxedClasses.getOrElse(c, c)

然后在case Some(value)

if(boxed(classTag.runtimeClass).isInstance(value))
  Some(value.asInstanceOf[U])

当然它无法区分你的地图Double和地图之间的区别java.lang.Double,因为这种区别不存在(编译时除外)。

于 2016-09-15T21:07:14.637 回答