加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

scala reflection-Mirrors,ClassTag,TypeTag and WeakTypeTag

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

    反射reflection是程序对自身的检查、验证甚至代码修改功能。反射可以通过它的Reify功能来实时自动构建生成静态的Scala实例如:类(class)、方法(method)、表达式(expression)等。或者动态跟踪当前程序运算事件如:方法运算(method invocation)、字段引用(field access)等。反射又分编译时段与运算时段反射即:compile-time-reflection及runtime-reflection。我们使用compile-time-reflection在编译程序时指导编译器修改编译中代码或者产生新的代码,用runtime-reflection来进行实例的类型匹配、验证等。在v2.10之前,Scala没有自备的Reflection工具库,只能用Java Reflection库提供的部分功能来动态检验类型(class)或对象(object)及使用它们的字段(member access)。但java-reflection无法提供对某些scala项目的支持如:function、trait以及特殊类型如:existential、high-kinder、path-dependent、abstract types。特别是java-reflection无法获取泛类型在runtime过程中的信息,这个一直是一个诟病。直到scala2.10增加了新的reflection库才从根本上解决了针对scala特性的反射(refective)功能问题。scala-reflection同样提供了compile-time-reflection和runtime-reflection。其中compile-time-reflection是通过独立的macro库实现的。在这篇讨论里我们主要介绍runtime-reflection功能。

scala runtime-reflection有以下几项主要功能:

1、动态检验对象类型,包括泛类型

2、实时构建类型实例

3、实时调用类型的运算方法

反射功能可以在两种环境下体现:compile-time及runtime,是通过反射库的universe命名空间分辨的,即:

runtime-reflection     : scala.reflect.runtime.universe

compile-time-reflection: scala.reflect.macros.universe

我们必须import相应的命名空间来获取compile-time或runtime反射功能。

各种具体的runtime反射功能是通过Mirror来获取的,以runtimeMirror(...)为入口。下面是各种Mirror的获取和使用方法示范:

 1  val ru = scala.reflect.runtime.universe
 2   //runtime reflection入口
 3   val m = ru.runtimeMirror(getClass.getClassLoader)  //m: ru.Mirror = JavaMirror with java.net.URLClassLoader...
 4   //sample class
 5   class Person(name: String, age: Int) {
 6     var hight: Double = 0.0
 7     def getName = name
 8   }
 9   val john = new Person("John", 23) {
10     hight = 1.7
11   }
12   //instance mirror
13   val im = m.reflect(john)
14   //im: ru.InstanceMirror = instance mirror for...
15   //query method on instance
16   val mgetName = ru.typeOf[Person].decl(ru.TermName("getName")).asMethod
17   //mgetName: ru.MethodSymbol = method getName
18   //get method
19   val invoke_getName = im.reflectMethod(mgetName) //invoke_getName: ru.MethodMirror = ...
20   invoke_getName()
21   //res0: Any = John
22   //query field on instance
23   val fldHight = ru.typeOf[Person].decl(ru.TermName("hight")).asTerm
24   //fldHight: ru.TermSymbol = variable hight
25   //get field
26   val fmHight = im.reflectField(fldHight) //fmHight: ru.FieldMirror = ...
27   fmHight.get //res1: Any = 1.7
28   fmHight.set(1.6)
29   fmHight.get
30   //res3: Any = 1.6
31   val clsP = ru.typeOf[Person].typeSymbol.asClass
32   //get class mirror
33   val cm = m.reflectClass(clsP)
34   //get constructor symbol
35   val ctorP = ru.typeOf[Person].decl(ru.nme.CONSTRUCTOR).asMethod
36   //get contructor mirror
37   val ctorm = cm.reflectConstructor(ctorP)
38   val mary = ctorm("mary", 20).asInstanceOf[Person]
39   println(mary.getName)    // mary
40   object OB {
41     def x = 3
42   }
43   //get object symbol
44   val objOB = ru.typeOf[OB.type].termSymbol.asModule
45   //get module mirror
46   val mOB = m.reflectModule(objOB)
47   //get object instance
48   val instOB = mOB.instance.asInstanceOf[OB.type]
49   println(instOB.x)  // 3

上面例子里的typeOf[T]和typeTag[T].tpe及implicitly[TypeTag[T]].tpe是通用的,看下面的示范: 

1   val clsP = ru.typeTag[Person].tpe.typeSymbol.asClass  //ru.typeOf[Person].typeSymbol.asClass
2   val clsP1 = implicitly[ru.TypeTag[Person]].tpe.typeSymbol.asClass //clsP1: ru.ClassSymbol = class Person
3   val clsP2 = ru.typeTag[Person].tpe.typeSymbol.asClass //clsP2: ru.ClassSymbol = class Person

讲到TypeTag[T],这本是一个由compiler产生的结构,可以把在编译时段(compile-time)类型T的所有信息带到运算时段(runtime)。主要目的可能是为了解决JVM在编译过程中的类型擦拭(type erasure)问题:在运算过程中可以从TypeTag[T]中获取T类型信息(通过typeTag[T]),最终实现类型T的对比验证等操作:

1  def getType[T: ru.TypeTag](obj: T) = ru.typeTag[T].tpe
2   //> getType: [T](obj: T)(implicit evidence$1: ru.TypeTag[T]) ru.Type
3  def getType2[T: ru.TypeTag](obj: T) = ru.typeOf[T]
4   //> getType2: [T](obj: T)(implicit evidence$2: ru.TypeTag[T]) ru.Type
5  getType(List(1,2)) =:= getType2(List(3,4))       //> res0: Boolean = true
6  getType(List(1,2)) =:= getType2(List(3.0,4.0))   //> res1: Boolean = false
7  getType(List(1,2)) =:= ru.typeOf[List[Int]]      //> res2: Boolean = true

以上是通过隐式参数(implicit parameters)或者上下文界线(context bound)来指示compiler产生TypeTag[T]结构的。

我们可能经常碰到TypeTag的调用例子,还有WeakTypeTag和ClassTag。ClassTag应该是有明显区别的,因为它在另外一个命名空间里:

1  import scala.reflect.ClassTag
2  def extract[T: ClassTag](list: List[Any]) =  list.flatMap {
3    case elem: T => Some(elem)
4    case _ => None
5  }    //> extract: [T](list: List[Any])(implicit evidence$3: scala.reflect.ClassTag[T] )List[T]
6  extract[String](List(1,"One",2,3,"Four",List(5)))//> res4: List[String] = List(One, Four)

(编辑:应用网_丽江站长网)

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

热点阅读