加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

scala reflection-Mirrors,ClassTag,TypeTag and WeakTypeTag

发布时间:2016-10-28 22:09:54 所属栏目:教程 来源:站长网
导读:副标题#e# 反射reflection是程序对自身的检查、验证甚至代码修改功能。反射可以通过它的Reify功能来实时自动构建生成静态的Scala实例如:类(class)、方法(method)、表达式(expression)等。或者动态跟踪当前程序运算事件如:方法运算(method invocati

ClassTag在scala.reflect.ClassTag里。这个extract函数的目的是把T类型的值过滤出来。上面的例子里list里的String元素被筛选出来了。但是如果我们像下面这样使用extract呢?

1 extract[List[Int]](List(List(1,2),List("a","b")))//> res5: List[List[Int]] = List(List(1, 2), List(a, b))

这次extract得出错误的运算结果,因为我们指明的是过滤List[Int]。这是因为ClassTag不支持高阶类型,List[Int]就是个高阶类型。那么extract[String]是怎样正确工作的呢?是因为compiler对模式匹配进行了这样的转换处理:

case elem: T >>> case elem @tag(_:T)

通过ClassTag[T]隐式实例(implicit instance)可以正确推导出elem的类型。在上面的例子里我们通过ClassTag得出T就是String。分析得出ClassTag可以分辨基础类型但无法分辨像List[Int],List[String]这样的高阶类型。

TypeTag包含了完整的类型信息可以分辨List[Int],List[String],甚至List[Set[Int]],List[Set[String]]这样的高阶类型。也就是TypeTag结构内包含了高阶类型内包嵌的类型,只有如此才能解决类型擦拭(type erasure)问题。我们用下面的例子来示范TypeTag的内容:

 1  def getInnerType[T: ru.TypeTag](obj: T) = ru.typeTag[T].tpe match {
 2    case ru.TypeRef(utype,usymb,args) =>
 3      List(utype,usymb,args).mkString("n")
 4  }      //> getInnerType: [T](obj: T)(implicit evidence$4: worksheets.reflect.ru.TypeTag[T])String
 5  getInnerType(List(1,2))                          //> res6: String = scala.collection.immutable.type
 6                                                   //| class List
 7                                                   //| List(Int)
 8  getInnerType(List(List(1,2)))                    //> res7: String = scala.collection.immutable.type
 9                                                   //| class List
10                                                   //| List(List[Int])
11  getInnerType(Set(List(1,2)))                     //> res8: String = scala.collection.immutable.type
12                                                   //| trait Set
13                                                   //| List(List[Int])
14  getInnerType(List(Set("a","b")))                 //> res9: String = scala.collection.immutable.type
15                                                   //| class List
16                                                   //| List(scala.collection.immutable.Set[java.lang.String])

上面的例子里getInnerType可以分辨高阶类型内的类型,args就是承载这个内部类型的List。那么如果我们为extract函数提供一个TypeTag又如何呢?看看下面的示范:

1  def extract[T: ru.TypeTag](list: List[Any]) =  list.flatMap {
2    case elem: T => Some(elem)
3    case _ => None
4  }    //> extract: [T](list: List[Any])(implicit evidence$3: ru.TypeTag[T])List[T]
5  extract[String](List(1,"One",2,3,"Four",List(5)))//> res4: List[String] = List(1, One, 2, 3, Four, List(5))
6  extract[List[Int]](List(List(1,2),List("a","b")))//> res5: List[List[Int]] = List(List(1, 2), List(a, b))

可以看到,虽然compiler产生并提供了TypeTag隐式参数evidence$3,但运算结果并不正确,这是为什么呢?从这个例子可以证实了ClassTag和TypeTag最大的区别:ClassTag在运算时提供了一个实例的类型信息,而TypeTag在运算时提供了一个类型的完整信息。我们只能用ClassTag来比较某个值的类型,而在运算时用TypeTag只能进行类型对比。extract中elem是List里的一个元素,是个值,所以只能用ClassTag来判别这个值的类型。如果使用TypeTag的话我们只能实现像下面示例中的类型对比:

 1  def meth[T: ru.TypeTag](xs: List[T]) = ru.typeTag[T].tpe match {
 2     case t if t =:= ru.typeOf[Int] => "list of integer"
 3     case t if t =:= ru.typeOf[List[String]] => "list of list of string"
 4     case t if t =:= ru.typeOf[Set[List[Int]]] => "list of set of list of integer"
 5     case _ => "some other types"
 6  }     //> meth: [T](xs: List[T])(implicit evidence$5: ru.TypeTag[T])String
 7  meth(List(1,2,3))                                //> res10: String = list of integer
 8  meth(List("a","b"))                              //> res11: String = some other types
 9  meth(List(List("a","a")))                        //> res12: String = list of list of string
10  meth(List(Set(List(1,20))))                      //> res13: String = list of set of list of integer

我们只能在运算时对T进行类型匹配。总结以上分析,ClassTag与TypeTag有下面几点重要区别:

1、ClassTag不适用于高阶类型:对于List[T],ClassTag只能分辨是个List,但无法获知T的类型。所以ClassTag不能用来解决类型擦拭(type erasure)问题

2、TypeTag通过完整的类型信息可以分辨高阶类型的内部类型,但它无法提供运算时(runtime)某个实例的类型。总的来说:TypeTag提供了runtime的类型信息,ClassTag提供runtime实例信息(所以ClassTag就像typeclass,能提供很多类型的隐型实例)

那么这个WeakTypeTag又是用来干什么的?它与TypeTag又有什么分别呢?如果我们把上面的meth函数改成使用WeakTypeTag:

 1  def meth[T: ru.WeakTypeTag](xs: List[T]) = ru.weakTypeTag[T].tpe match {
 2     case t if t =:= ru.typeOf[Int] => "list of integer"
 3     case t if t =:= ru.typeOf[List[String]] => "list of list of string"
 4     case t if t =:= ru.typeOf[Set[List[Int]]] => "list of set of list of integer"
 5     case _ => "some other types"
 6  }      //> meth: [T](xs: List[T])(implicit evidence$5: ru.WeakTypeTag[T])String
 7  meth(List(1,2,3))                                //> res10: String = list of integer
 8  meth(List("a","b"))                              //> res11: String = some other types
 9  meth(List(List("a","a")))                        //> res12: String = list of list of string
10  meth(List(Set(List(1,20))))                      //> res13: String = list of set of list of integer

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读