我试图将类型标记转换为维护/保留正常擦除类型参数的java类。有很多图书馆可以从像这样的转换中受益(比如Jackson和Guice)。我目前正在尝试将基于Manifest
的代码迁移到TypeTag
,因为Manifest
不足以应对某些极端情况。
与其他数据类型相比,JVM将Arrays视为特殊对象。 classOf[Int]
和classOf[Array[Int]]
之间的区别在于方法Class.isArray()
将为后者返回true。
Manifest
实施很简单。 Manifest.erasure
是Class
个实例,其中isArray()
已经有效/无效。
TypeTag
实施比较棘手。没有快捷简便的erasure
方法。事实上,类似的' TypeTag变体RuntimeMirror.runtimeClass
不希望代表我们处理创建任何基于数组的类。阅读文档:
注意:如果Scala符号是ArrayClass,则为ClassNotFound异常 抛出因为没有与Scala对应的唯一Java类 通用数组
要解决这个问题,我尝试检测它是否是一个数组。如果是数组,那么我手动创建类对象。但是,当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的类型参数为Array?
此外,在这种情况下,类实例会是什么样子?它是一个数组[对象]吗?
答案 0 :(得分:4)
再次分解:
scala> innerType match { case TypeRef(pre, sym, args) => sym == definitions.ArrayClass }
res13: Boolean = true
这可能让你分道扬。
答案 1 :(得分:0)
另一种方法是比较 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