如何检查 Scala HigherKinded TypeTag 是否为数组?
How do I check if a Scala HigherKinded TypeTag is an Array?
我正在尝试将类型标记转换为 java class maintains/persists 通常擦除的类型参数。有相当多的库受益于此类转换(例如 Jackson 和 Guice)。我目前正在尝试将基于 Manifest
的代码迁移到 TypeTag
,因为 Manifest
不足以应对某些特殊情况。
与其他数据类型相比,JVM 特殊对待数组。 classOf[Int]
和 classOf[Array[Int]]
之间的区别在于方法 Class.isArray()
将 return 为后者。
Manifest
实现很简单。 Manifest.erasure
是一个 Class
实例,其中 isArray()
已经是 valid/true。
TypeTag
实现比较棘手。没有快速简便的 erasure
方法。事实上,'similar' TypeTag 变体 RuntimeMirror.runtimeClass
不喜欢代表我们处理创建任何基于数组的 classes。阅读文档:
Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is
thrown because there is no unique Java class corresponding to a Scala
generic array
为了解决这个问题,我尝试检测它是否是一个数组。如果它是一个数组,那么我手动创建 class 对象。但是,当 Array 具有未知类型参数时,我遇到了一个额外的边缘情况。
首先让我给你看一个不是 HigherKinded 类型的例子。
import scala.reflect.runtime.universe._
class A[T]
val innerType = typeOf[A[Array[_]]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns true.
到目前为止一切顺利。
class B[T[_]]
val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns false.
我无法创建 typeOf[Array],因为它抱怨缺少参数。如何检测 B 的类型参数为数组?
此外,class 实例在这种情况下会是什么样子?它是数组[对象]吗?
再次分解:
scala> innerType match { case TypeRef(pre, sym, args) => sym == definitions.ArrayClass }
res13: Boolean = true
这可能会让你中途离开。
另一种方法是比较 typeConstructors:
import scala.reflect.runtime.universe._
class B[T[_]]
val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType.typeConstructor =:= typeOf[Array[_]].typeConstructor
innerType: reflect.runtime.universe.Type = Array
res4: Boolean = true
当我们需要检测类型是数组(任何类型)时,这通常也适用。
尝试获取此类 innerType 的擦除类型(进行比较)对 Array 失败(但对其他 HigherKinded 类型有效):
class B[T[_]]
val innerType = typeOf[B[Array]].typeArgs.head
innerType.typeArgs
innerType.erasure // fails
innerType.erasure =:= typeOf[Array[_]].erasure
defined class B
innerType: reflect.runtime.universe.Type = Array
res4: List[reflect.runtime.universe.Type] = List()
java.util.NoSuchElementException: head of empty list
at scala.collection.immutable.Nil$.head(List.scala:431)
at scala.collection.immutable.Nil$.head(List.scala:428)
at scala.reflect.internal.transform.Erasure$ErasureMap.apply(Erasure.scala:126)
at scala.reflect.internal.transform.Transforms$class.transformedType(Transforms.scala:43)
at scala.reflect.internal.SymbolTable.transformedType(SymbolTable.scala:16)
at scala.reflect.internal.Types$TypeApiImpl.erasure(Types.scala:225)
at scala.reflect.internal.Types$TypeApiImpl.erasure(Types.scala:218)
... 36 elided
我正在尝试将类型标记转换为 java class maintains/persists 通常擦除的类型参数。有相当多的库受益于此类转换(例如 Jackson 和 Guice)。我目前正在尝试将基于 Manifest
的代码迁移到 TypeTag
,因为 Manifest
不足以应对某些特殊情况。
与其他数据类型相比,JVM 特殊对待数组。 classOf[Int]
和 classOf[Array[Int]]
之间的区别在于方法 Class.isArray()
将 return 为后者。
Manifest
实现很简单。 Manifest.erasure
是一个 Class
实例,其中 isArray()
已经是 valid/true。
TypeTag
实现比较棘手。没有快速简便的 erasure
方法。事实上,'similar' TypeTag 变体 RuntimeMirror.runtimeClass
不喜欢代表我们处理创建任何基于数组的 classes。阅读文档:
Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown because there is no unique Java class corresponding to a Scala generic array
为了解决这个问题,我尝试检测它是否是一个数组。如果它是一个数组,那么我手动创建 class 对象。但是,当 Array 具有未知类型参数时,我遇到了一个额外的边缘情况。
首先让我给你看一个不是 HigherKinded 类型的例子。
import scala.reflect.runtime.universe._
class A[T]
val innerType = typeOf[A[Array[_]]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns true.
到目前为止一切顺利。
class B[T[_]]
val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns false.
我无法创建 typeOf[Array],因为它抱怨缺少参数。如何检测 B 的类型参数为数组?
此外,class 实例在这种情况下会是什么样子?它是数组[对象]吗?
再次分解:
scala> innerType match { case TypeRef(pre, sym, args) => sym == definitions.ArrayClass }
res13: Boolean = true
这可能会让你中途离开。
另一种方法是比较 typeConstructors:
import scala.reflect.runtime.universe._
class B[T[_]]
val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType.typeConstructor =:= typeOf[Array[_]].typeConstructor
innerType: reflect.runtime.universe.Type = Array
res4: Boolean = true
当我们需要检测类型是数组(任何类型)时,这通常也适用。
尝试获取此类 innerType 的擦除类型(进行比较)对 Array 失败(但对其他 HigherKinded 类型有效):
class B[T[_]]
val innerType = typeOf[B[Array]].typeArgs.head
innerType.typeArgs
innerType.erasure // fails
innerType.erasure =:= typeOf[Array[_]].erasure
defined class B
innerType: reflect.runtime.universe.Type = Array
res4: List[reflect.runtime.universe.Type] = List()
java.util.NoSuchElementException: head of empty list
at scala.collection.immutable.Nil$.head(List.scala:431)
at scala.collection.immutable.Nil$.head(List.scala:428)
at scala.reflect.internal.transform.Erasure$ErasureMap.apply(Erasure.scala:126)
at scala.reflect.internal.transform.Transforms$class.transformedType(Transforms.scala:43)
at scala.reflect.internal.SymbolTable.transformedType(SymbolTable.scala:16)
at scala.reflect.internal.Types$TypeApiImpl.erasure(Types.scala:225)
at scala.reflect.internal.Types$TypeApiImpl.erasure(Types.scala:218)
... 36 elided