Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何手动创建TypeTag?_Scala - Fatal编程技术网

Scala 如何手动创建TypeTag?

Scala 如何手动创建TypeTag?,scala,Scala,我对手动创建TypeTag感兴趣(从2.10M5开始): scalac-Xprint:typer.scala生成 package <empty> { object X extends scala.AnyRef { def <init>(): X.type = { X.super.<init>(); () }; import scala.reflect.runtime.`package`.universe._;

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

scalac-Xprint:typer.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
  }
}
包{
对象X扩展了scala.AnyRef{
def():X.type={
超级(;
()
};
导入scala.reflect.runtime.`package`.universe.\u;
def tt[A>:Nothing 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{
最后一个类$TypeCreator 1扩展了TypeCreator{
def():$typecreator1={
$typecreator1.super.();
()
};
def apply[U>:无字符串]=X.this.t
}
}

因为类型是硬编码的,所以它看起来完全是编译器的魔法。然而,有没有办法手动执行此操作?

函数定义

def tt[A : TypeTag](a: A) = typeTag[A]
这只是另一种写作方式

def tt(a: A)(implicit tag: TypeTag[A]) = tag
这意味着标记的实例是由编译器隐式创建的。其背后的原因是Scala编译器通过硬编码其他被擦除的类型信息来解决JVM的类型擦除问题


如果您不熟悉类型擦除问题,则可能是JVM不存储类型参数信息,例如,类型
Seq[Set[Int]]
将被简单地看作
Seq[\ux]
,您将无法通过反射找到丢失的类型信息。

在M3中,您可以用一种非常简单的方式创建类型标记,例如:
TypeTag[Int](TypeRef(,Nil))
。这基本上意味着一旦创建了类型标记,它将永远绑定到某个类加载器(即上面示例中用于加载scala.Int符号的那个)

当时很好,因为我们认为我们可以有一个容纳所有类加载器的一刀切的镜像。这很方便,因为您可以隐式地编写
[TypeTag[T]
,编译器将使用该全局镜像实例化您请求的类型

不幸的是,后来根据反馈,我们意识到这是行不通的,我们需要多个镜像——每个镜像都有自己的类加载器

然后很明显,类型标记需要灵活,因为一旦您隐式地编写了
类型标记[T]]
编译器就没有足够的信息来说明您想要使用什么样的类加载器。基本上有两种选择:1)使类型标记路径依赖于镜像(因此,每次从编译器请求类型标记时,都必须显式地提供一个镜像),2)将类型标记转换为类型工厂,能够在任何镜像中实例化它们自己。长话短说,第一个选项不起作用,所以我们就到了现在的位置

因此,当前需要以一种非常迂回的方式创建类型标记,如中所述。您可以调用在附带的
TypeTag
中定义的工厂方法,并提供两个参数:1)默认镜像,其中类型标记将被实例化;2)可以在任意镜像中实例化类型标记的类型工厂。这基本上是编译器在上面附加的打印输出中所做的

为什么我称之为这个迂回?因为要提供类型工厂,您需要手动将
scala.reflect.base.TypeFactory
类分为子类。这是scala类型系统在函数和依赖类型方法之间的一个不幸限制。

基于:

这适用于Scala 2.10.2:

scala> inside(typeTag[(Int, Double)])
res0: (reflect.runtime.universe.TypeTag[Int], reflect.runtime.universe.TypeTag[Double]) = (TypeTag[Int],TypeTag[Double])

只要您没有多个
类加载器
s,那么绑定到特定
镜像
的限制可能不是问题。

目前,有三种方法可以手动创建支持泛型的
类型标签
。前两种方法依赖于
scala编译器
,并使用它们u获取类型检查,就像在编译时一样,因为它是实际的代码编译:

如果您需要一个可序列化的
TypeTag
,并且性能不是您主要关心的问题,那么第一种方法是最简洁的。另外,如果您的用例需要非常高的性能,请注意动态编译可能需要几秒钟才能完成

第二种方法的性能稍好一些:

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]
    }
  }
}

我不认为这个答案完全正确,因为有一种方法可以手动创建清单,而清单也是由编译器自动创建的:
newmanifest[Int]{def erasure=classOf[Int]}
(这在2.10中不再有效)我不确定我是否理解您在这里试图实现的目标。当然,您可以手动实例化一个类
TypeTag
,但它的唯一目的是由编译器在幕后实例化,编译器会生成与大小写相关的信息。如果出于任何目的,您试图模拟它,那么您的反编译
私有[此]val t:reflect.runtime.universe.TypeTag
声明准确地展示了如何实现它,但这并不是该类的预期使用方式。这方面的一个用例可能是使用Scala方法,该方法需要Java端的TypeTag。我想:也许有一种比编译器更简单/另一种方式来实现它。如果您是如果您想使用Java源代码中的Scala类型上的Scala反射api,那么您最好的选择是通过Scala中的某个自定义api类来接口需要隐式证据的方法。如果您试图在Java中的Java类型上使用Scala反射,它根本不起作用。但是,无论哪种方法,使用Java中的Scala反射都不是一个好方法想法。我明白了,Scala反射比我现在能想到的要复杂得多。我仍然要花很多时间才能弄清楚那里发生了什么……你能详细说明一下你的用例吗?构建
def inside[A, B](tag: TypeTag[(A, B)]): (TypeTag[A], TypeTag[B]) = {
  val tpes = tag.tpe.asInstanceOf[TypeRefApi].args
  val tagA = typeToTypeTag[A](tpes(0), tag.mirror)
  val tagB = typeToTypeTag[B](tpes(1), tag.mirror)
  return (tagA, tagB)
}
scala> inside(typeTag[(Int, Double)])
res0: (reflect.runtime.universe.TypeTag[Int], reflect.runtime.universe.TypeTag[Double]) = (TypeTag[Int],TypeTag[Double])
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[_]]
}
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]
    }
  }
}
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]
    }
  })
}