scala reflection-Mirrors,ClassTag,TypeTag and WeakTypeTag
副标题[/!--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) (编辑:淮北站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |