scala typetag java,Scala:什么是TypeTag,我如何使用它?

A TypeTag解决了Scala的类型在运行时被擦除的问题(类型擦除)。如果我们想class Fooclass Bar extends Foodef meth[A](xs: List[A]) = xs match {

case _: List[String] => "list of strings"

case _: List[Foo] => "list of foos"}

我们会收到警告::23: warning: non-variable type argument String in type pattern List[String]↩

is unchecked since it is eliminated by erasure         case _: List[String] => "list of strings"

^:24: warning: non-variable type argument Foo in type pattern List[Foo]↩

is unchecked since it is eliminated by erasure         case _: List[Foo] => "list of foos"

^

解决这个问题舱单被介绍给斯卡拉。但是,它们的问题是不能表示许多有用的类型,比如路径依赖的类型:scala> class Foo{class Bar}defined class Fooscala> def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev

warning: there were 2 deprecation warnings; re-run with -deprecation for details

m: (f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar])Manifest[f.Bar]scala> val f1 = new Foo;val b1 = new f1.Barf1: Foo = Foo@681e731c

b1: f1.Bar = Foo$Bar@271768ab

scala> val f2 = new Foo;val b2 = new f2.Barf2: Foo = Foo@3e50039c

b2: f2.Bar = Foo$Bar@771d16b9

scala> val ev1 = m(f1)(b1)warning: there were 2 deprecation warnings; re-run with -deprecation for details

ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Barscala> val ev2 = m(f2)(b2)warning: there were 2 deprecation warnings; re-run with -deprecation for details

ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Barscala> ev1 == ev2 // they should be different, thus the result is wrongres28: Boolean = true

因此,他们被泰普塔格,它们既易于使用,又很好地集成到新的反射API中。利用它们,我们可以巧妙地解决上述路径依赖类型的问题:scala> def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev

m: (f: Foo)(b: f.Bar)(implicit ev: reflect.runtime.universe.TypeTag[f.Bar])↩

reflect.runtime.universe.TypeTag[f.Bar]scala> val ev1 = m(f1)(b1)ev1: reflect.runtime.universe.TypeTag[f1.Bar] = TypeTag[f1.Bar]scala> val ev2 = m(f2)(b2)ev2: reflect.runtime.universe.TypeTag[f2.Bar] = TypeTag[f2.Bar]scala> ev1 == ev2 // the result is correct, the type tags are differentres30: Boolean = falsescala> ev1.tpe =:= ev2.tpe // this result is correct, toores31: Boolean = false

它们还易于用于检查类型参数:import scala.reflect.runtime.universe._def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {

case t if t =:= typeOf[String] => "list of strings"

case t if t <:> "list of foos"}scala> meth(List("string"))res67: String = list of strings

scala> meth(List(new Bar))res68: String = list of foos

在这一点上,理解使用是非常重要的。=:=(类型相等)和<:> typeOf[List[java.lang.String]] =:= typeOf[List[Predef.String]]res71: Boolean = truescala> typeOf[List[java.lang.String]] == typeOf[List[Predef.String]]res72: Boolean = false

后者检查结构是否相等,这通常不是应该做的事情,因为它不关心前缀之类的事情(如示例中的情况)。

A TypeTag完全由编译器生成,这意味着编译器将创建并填充TypeTag当调用一个方法时,需要这样的TypeTag..标签有三种不同的形式:

ClassTag代用品ClassManifest鉴于TypeTag或多或少是替换Manifest.

前者允许完全使用泛型数组:scala> import scala.reflect._import scala.reflect._

scala> def createArr[A](seq: A*) = Array[A](seq: _*):22: error: No ClassTag available for A       def createArr[A](seq: A*) = Array[A](seq: _*)

^scala> def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*)createArr: [A](seq: A*)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]scala> createArr(1,2,3)res78: Array[Int] = Array(1, 2, 3)scala> createArr("a","b","c")res79: Array[String] = Array(a, b, c)

ClassTag只提供在运行时创建类型所需的信息(类型被擦除):scala> classTag[Int]res99: scala.reflect.ClassTag[Int] = ClassTag[int]scala> classTag[Int].runtimeClass

res100: Class[_] = int

scala> classTag[Int].newArray(3)res101: Array[Int] = Array(0, 0, 0)scala> classTag[List[Int]]res104: scala.reflect.ClassTag[List[Int]] =↩        ClassTag[class scala.collection.immutable.List]

正如我们在上面看到的,他们不关心类型擦除,因此如果想要“完全”类型TypeTag应使用:scala> typeTag[List[Int]]res105: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]scala> typeTag[List[Int]].tpe

res107: reflect.runtime.universe.Type = scala.List[Int]scala> typeOf[List[Int]]res108: reflect.runtime.universe.Type = scala.List[Int]scala> res107 =:= res108

res109: Boolean = true

如人们所见,方法tpe的TypeTag结果充分Type,这和我们得到的是一样的typeOf叫做。当然,两者都有可能,ClassTag和TypeTag:scala> def m[A : ClassTag : TypeTag] = (classTag[A], typeTag[A])m: [A](implicit evidence$1: scala.reflect.ClassTag[A],↩       implicit evidence$2: reflect.runtime.universe.TypeTag[A])↩      (scala.reflect.ClassTag[A], reflect.runtime.universe.TypeTag[A])scala> m[List[Int]]res36: (scala.reflect.ClassTag[List[Int]],↩

reflect.runtime.universe.TypeTag[List[Int]]) =↩       (scala.collection.immutable.List,TypeTag[scala.List[Int]])

现在剩下的问题是,WeakTypeTag?总之,TypeTag表示具体类型(这意味着它只允许完全实例化类型)WeakTypeTag只允许任何类型。大多数情况下,一个人不在乎什么是什么(这意味着TypeTag),但是,例如,当使用应该与泛型类型一起工作的宏时,需要:object Macro {

import language.experimental.macros  import scala.reflect.macros.Context

def anymacro[A](expr: A): String = macro __anymacro[A]

def __anymacro[A : c.WeakTypeTag](c: Context)(expr: c.Expr[A]): c.Expr[A] = {

// to get a Type for A the c.WeakTypeTag context bound must be added

val aType = implicitly[c.WeakTypeTag[A]].tpe    ???

}}

如果一个人取代了WeakTypeTag带着TypeTag引发错误::17: error: macro implementation has wrong shape:

required: (c: scala.reflect.macros.Context)(expr: c.Expr[A]): c.Expr[String]

found   : (c: scala.reflect.macros.Context)(expr: c.Expr[A])(implicit evidence$1: c.TypeTag[A]): c.Expr[A]macro implementations cannot have implicit parameters other than WeakTypeTag evidences             def anymacro[A](expr: A): String = macro __anymacro[A]

^

Scala的正式文档站点还包含一个反射指南.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值