我们的库使用TypeTags,但现在我们需要与需要清单的另一个库进行交互。有没有简单的方法从TypeTag创建清单?
答案 0 :(得分:11)
如果您在Manifest
出现时尝试天真地召唤TypeTag
,编译器会给出关于解决方案的提示:
import reflect.runtime.universe._
import reflect.ClassTag
def test[A : TypeTag] = manifest[A]
error: to create a manifest here, it is necessary to interoperate with the type
tag `evidence$1` in scope.
however typetag -> manifest conversion requires a class tag for the corresponding
type to be present.
to proceed add a class tag to the type `A` (e.g. by introducing a context bound)
and recompile.
def test[A : TypeTag] = manifest[A]
^
因此,如果范围内有ClassTag
,编译器将能够创建必要的Manifest
。您有两种选择:
在TypeTag
处添加第二个上下文,如:
def test[A : TypeTag : ClassTag] = manifest[A] // this compiles
或首先将TypeTag
转换为ClassTag
,然后要求Manifest
:
def test[A](implicit ev: TypeTag[A]) = {
// typeTag to classTag
implicit val cl = ClassTag[A]( ev.mirror.runtimeClass( ev.tpe ) )
// with an implicit classTag in scope, you can get a manifest
manifest[A]
}
答案 1 :(得分:3)
gourlaysama的anwer使用Class [_],因此类型参数正在被删除。我想出了一个保留类型参数的实现:How to maintain type parameter during TypeTag to Manifest conversion?
以下是代码:
def toManifest[T:TypeTag]: Manifest[T] = {
val t = typeTag[T]
val mirror = t.mirror
def toManifestRec(t: Type): Manifest[_] = {
val clazz = ClassTag[T](mirror.runtimeClass(t)).runtimeClass
if (t.typeArgs.length == 1) {
val arg = toManifestRec(t.typeArgs.head)
ManifestFactory.classType(clazz, arg)
} else if (t.typeArgs.length > 1) {
val args = t.typeArgs.map(x => toManifestRec(x))
ManifestFactory.classType(clazz, args.head, args.tail: _*)
} else {
ManifestFactory.classType(clazz)
}
}
toManifestRec(t.tpe).asInstanceOf[Manifest[T]]
}