gpt4 book ai didi

scala - 如何手动创建 TypeTag?

转载 作者:行者123 更新时间:2023-12-04 00:06:09 27 4
gpt4 key购买 nike

我对手动创建 TypeTag 感兴趣(从 2.10M5 开始):

object X {
import reflect.runtime.universe._
def tt[A : TypeTag](a: A) = typeTag[A] // how to do this manually?
val t = tt(List("")(_))
}
scalac -Xprint:typer <file>.scala结果是
package <empty> {
object X extends scala.AnyRef {
def <init>(): X.type = {
X.super.<init>();
()
};
import scala.reflect.runtime.`package`.universe._;
def tt[A >: Nothing <: Any](a: A)(implicit evidence$1: reflect.runtime.universe.TypeTag[A]): reflect.runtime.universe.TypeTag[A] = scala.reflect.runtime.`package`.universe.typeTag[A](evidence$1);
private[this] val t: reflect.runtime.universe.TypeTag[Int => String] = X.this.tt[Int => String](((x$1: Int) => immutable.this.List.apply[String]("").apply(x$1)))({
val $u: reflect.runtime.universe.type = scala.this.reflect.runtime.`package`.universe;
val $m: $u.Mirror = scala.this.reflect.runtime.`package`.universe.runtimeMirror(this.getClass().getClassLoader());
$u.TypeTag.apply[Int => String]($m, {
final class $typecreator1 extends TypeCreator {
def <init>(): $typecreator1 = {
$typecreator1.super.<init>();
()
};
def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = {
val $u: U = $m$untyped.universe;
val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
$u.TypeRef.apply($u.ThisType.apply($m.staticModule("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Function1"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor, $m.staticClass("java.lang.String").asTypeSymbol.asTypeConstructor))
}
};
new $typecreator1()
})
});
<stable> <accessor> def t: reflect.runtime.universe.TypeTag[Int => String] = X.this.t
}
}

这似乎完全是编译器的魔法,因为类型是硬编码的。不过有没有办法手动做到这一点?

最佳答案

目前,创建 TypeTag 的方法有 3 种。 支持泛型 手动。前两个取决于 scala-compiler ,并且使用它们,您可以像在编译时一样进行类型检查,因为它是实际的代码编译:

import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox

val toolbox = currentMirror.mkToolBox()

def createTypeTag(tp: String): TypeTag[_] = {
val ttree = toolbox.parse(s"scala.reflect.runtime.universe.typeTag[$tp]")
toolbox.eval(ttree).asInstanceOf[TypeTag[_]]
}

如果你需要一个可序列化的 TypeTag性能不是您主要关心的问题,第一种方法是最简洁的。 OTOH,如果您的用例需要非常高性能,请注意即时编译可能需要几秒钟才能完成。

第二种方法执行得更好一些:
def createTypeTag(tp: String): TypeTag[_] = {
val ttagCall = s"scala.reflect.runtime.universe.typeTag[$tp]"
val tpe = toolbox.typecheck(toolbox.parse(ttagCall), toolbox.TYPEmode).tpe.resultType.typeArgs.head

TypeTag(currentMirror, new reflect.api.TypeCreator {
def apply[U <: reflect.api.Universe with Singleton](m: reflect.api.Mirror[U]) = {
assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.")
tpe.asInstanceOf[U#Type]
}
}
}

第二种模式创建一个类型树并获取在 TypeTag 中标记的具体类型。 ,即,如果您的目标是 List[String] , 会被翻译成 scala.collection.immutable.List[String] , 自 scala.List只是一个类型别名。这实际上是 typeTag[List[String]] 所期望的行为。 .

最后一种方法是创建一个 Type手动并使用它来创建 TypeTag .此方法容易出错,类型检查有限,并且使用内部 API。然而,这是手动获取 TypeTag 的最快方法。 .
def createTypeTag(tp: String): TypeTag[_] = {
val typs = // ... manipulate the string to extract type and parameters
val typSym = currentMirror.staticClass(typs[0])
val paramSym = currentMirror.staticClass(typs[1])

val tpe = universe.internal.typeRef(NoPrefix, typSym, List(paramSym.selfType))

val ttag = TypeTag(currentMirror, new TypeCreator {
override def apply[U <: Universe with Singleton](m: Mirror[U]): U#Type = {
assert(m == currentMirror, s"TypeTag[$tpe] defined in $currentMirror cannot be migrated to $m.")
tpe.asInstanceOf[U#Type]
}
})
}

关于scala - 如何手动创建 TypeTag?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11494788/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com