【问题标题】:ClassTag.runtimeClass.isInstance does not work for AnyValClassTag.runtimeClass.isInstance 不适用于 AnyVal
【发布时间】:2016-09-15 19:56:50
【问题描述】:

使用 scala ClassTags 我发现当您将它与 AnyVal 对象一起使用时,classTag.runtimeClass.isInstance 无法正常工作。这是一个sn-p,您可以在其中对其进行测试。有什么想法可以使它适用于 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

【问题讨论】:

  • 这是一个 Scala 错误吗?
  • 使用 isInstanceOf 代替 isInstance stackoverflow.com/questions/26168721/…
  • 不能使用value.isInstanceOf[U],因为它是泛型类型,所以我需要使用classtag(value.isInstanceOf[U]是unchecked,因为被擦除消除了)跨度>
  • 似乎是Double类型不对? extractField[java.lang.Double](map,"k1") 返回Some(2.0)。我不知道发生了什么 - 我认为 scala.Double 基本上可以与 java.lang.Double 互换?只是为了测试 Samar 的建议,使用 if(classTag.runtimeClass.isInstanceOf[U]) 可以得到像这样的时髦结果:extractField[String](map,"k1") //Returned Some(2.0) 所以这是行不通的。
  • classTag.runtimeClass.isInstanceOf[U] 将始终返回 true,因为 classtag 属于 U 类,我要检查的是 value 是否属于 U 类型。在另一篇文章中,一个人说:“如果您有一个泛型类型,并且您想“传递”一种方法来测试一个值是否属于该类(将通过 isInstanceOf 测试),您可以使用 scala.reflect.ClassTag 代替。ClassTags 有点像类,除了他们知道 Scala 拳击和其他一些东西。(如果需要,我可以详细说明 ClassTag,但您应该在其他地方找到有关它们的信息。)“但它没有说明如何制作它

标签: scala generics scala-reflect


【解决方案1】:

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

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

isInstance 采用ObjectclassOf[Double] 代表 JVM 原语 double 的“类”(和 classTag[Double].runtimeClass 相同)。由于对象不能是基元,classOf[Double].isInstance(something) 将始终为 false。

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])

当然它无法区分您的映射中的Doublejava.lang.Double,因为这种区别不存在(编译时除外)。

【讨论】:

  • 有没有办法对 AnyVal 对象进行这种检查?
  • 我添加了一个解决方案。
  • 谢谢,成功了!我很惊讶这个棘手的解决方案是做到这一点的唯一方法......
  • 现代成语是def f[A: ClassTag](x: Option[Any]) = x match { case Some(_: A) => true case _ => false }。这仅在 2.10 上被破坏。
  • @som-snytt 啊,对。不记得这里适用。
猜你喜欢
  • 2021-02-15
  • 2012-11-26
  • 1970-01-01
  • 2019-06-24
  • 2014-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多