在泛型函数中转换数据类型时无效。调用了 toint,但 v 的类型仍然是 double
Invalid when I convert a data type in a generic function. toint is called, but the type of v is still double
我想实现一种将 JSON 数据转换为 Scala 内置对象的方法。代码类似如下:
implicit class JsonNodeToScala(jsonNode: JsonNode) {
import scala.jdk.CollectionConverters._
import scala.reflect.{ClassTag,classTag}
def toSeq[T: ClassTag]: Seq[Option[T]] = jsonNode.elements.asScala.map(_.toScala[T]).toSeq
def toMap[T: ClassTag]: Map[String, Option[T]] = jsonNode.fields.asScala.map(field => (field.getKey, field.getValue.toScala[T])).toMap
def toScala[T: ClassTag]: Option[T] = (this.jsonNode match {
case v if v.isBoolean => v.asBoolean
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => v
}
case v if v.isTextual => v.asText
case jsonNode => jsonNode
}) match {
case v: T => Some(v)
case v =>
println(v, classTag.runtimeClass, v.getClass)
None
}
}
我按如下方式使用时有效
new ObjectMapper().readTree("""[1,2,null,4]""").toSeq[Double]
>>> res136: Seq[Option[Double]] = List(
Some(value = 1.0),
Some(value = 2.0),
None,
Some(value = 4.0)
)
但是当我传入泛型参数int时,却得不到我想要的结果
new ObjectMapper().readTree("""[1,2,null,4]""").toSeq[Int]
>>>
toInt(1.0,int,class java.lang.Double)
toInt(2.0,int,class java.lang.Double)
(null,int,class com.fasterxml.jackson.databind.node.NullNode)
toInt(4.0,int,class java.lang.Double)
res138: Seq[Option[Int]] = List(None, None, None, None)
结果调用了toint,但是v的类型还是double。是不是Scala处理match case的原因?
如果我想满足我的需求,我应该如何修改我的代码?
"[1, 2, 3]" call toSeq[Int] => Seq(1, 2, 3)
"[1, 2, 3]" call toSeq[Double] => Seq(1.0, 2.0, 3.0)
"[1.0, 2.0, 3.0]" call toSeq[Int] => Seq(1, 2, 3)
"[1.0, 2.0, 3.0]" call toSeq[Double] => Seq(1.0, 2.0, 3.0)
这里的主要问题是:
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => v
}
Scala 编译器必须找到 Int
、Long
和 Double
之间的共同最低祖先。
在 Scala 2.12 中,它恰好是 Double
,因此它再次将 Int
转换为 Double
(通过隐式转换)。
欺骗 编译器的一种方法应该是向上转换一些 return 类型,这样它就不能在数值类型之间执行隐式类型转换。例如:
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => (v : Any) // common lowest type now is Any, no conversions will be performed
}
我想实现一种将 JSON 数据转换为 Scala 内置对象的方法。代码类似如下:
implicit class JsonNodeToScala(jsonNode: JsonNode) {
import scala.jdk.CollectionConverters._
import scala.reflect.{ClassTag,classTag}
def toSeq[T: ClassTag]: Seq[Option[T]] = jsonNode.elements.asScala.map(_.toScala[T]).toSeq
def toMap[T: ClassTag]: Map[String, Option[T]] = jsonNode.fields.asScala.map(field => (field.getKey, field.getValue.toScala[T])).toMap
def toScala[T: ClassTag]: Option[T] = (this.jsonNode match {
case v if v.isBoolean => v.asBoolean
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => v
}
case v if v.isTextual => v.asText
case jsonNode => jsonNode
}) match {
case v: T => Some(v)
case v =>
println(v, classTag.runtimeClass, v.getClass)
None
}
}
我按如下方式使用时有效
new ObjectMapper().readTree("""[1,2,null,4]""").toSeq[Double]
>>> res136: Seq[Option[Double]] = List(
Some(value = 1.0),
Some(value = 2.0),
None,
Some(value = 4.0)
)
但是当我传入泛型参数int时,却得不到我想要的结果
new ObjectMapper().readTree("""[1,2,null,4]""").toSeq[Int]
>>>
toInt(1.0,int,class java.lang.Double)
toInt(2.0,int,class java.lang.Double)
(null,int,class com.fasterxml.jackson.databind.node.NullNode)
toInt(4.0,int,class java.lang.Double)
res138: Seq[Option[Int]] = List(None, None, None, None)
结果调用了toint,但是v的类型还是double。是不是Scala处理match case的原因?
如果我想满足我的需求,我应该如何修改我的代码?
"[1, 2, 3]" call toSeq[Int] => Seq(1, 2, 3)
"[1, 2, 3]" call toSeq[Double] => Seq(1.0, 2.0, 3.0)
"[1.0, 2.0, 3.0]" call toSeq[Int] => Seq(1, 2, 3)
"[1.0, 2.0, 3.0]" call toSeq[Double] => Seq(1.0, 2.0, 3.0)
这里的主要问题是:
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => v
}
Scala 编译器必须找到 Int
、Long
和 Double
之间的共同最低祖先。
在 Scala 2.12 中,它恰好是 Double
,因此它再次将 Int
转换为 Double
(通过隐式转换)。
欺骗 编译器的一种方法应该是向上转换一些 return 类型,这样它就不能在数值类型之间执行隐式类型转换。例如:
case v if v.isNumber =>
(v.asDouble, classTag.runtimeClass) match {
case (v, c) if c == classOf[Int] =>
print("toInt")
v.toInt
case (v, c) if c == classOf[Long] =>
print("toLong")
v.toLong
case (v, _) => (v : Any) // common lowest type now is Any, no conversions will be performed
}