类型符号和Scala反射镜之间的关系

类型符号和Scala反射镜之间的关系

问题描述:

Scala反射非常复杂。它包含类型符号和镜像。你能告诉我他们之间的关系吗?类型符号和Scala反射镜之间的关系

在使用Scala Reflection API时,如果您使用了Java反射API,您会遇到更多类型的用法。鉴于你开始用含有类的完全限定类名称的String的示例场景,这些都是你很可能会遇到类型:

  • Universe:斯卡拉支持运行时和编译时反射。通过从相应的Universe导入,您可以选择您正在进行的反射。对于运行时反射,这对应于scala.reflect.runtime包,对于编译时反射它对应于scala.reflect.macros包。这个答案关注前者。

    与Java一样,您通常会通过选择要反映的ClassLoader的类来启动任何反射。 Scala提供了一个使用当前类的ClassLoader的快捷方式:scala.reflect.runtime.currentMirror,这会给你一个Mirror(稍后的更多镜像)。许多JVM应用程序只使用一个类加载器,所以这是Scala Reflection API的一个常用入口点。由于您从runtime导入,您现在处于该宇宙中。

  • Symbols:符号包含关于您想要反映的任何静态元数据。这包括任何你能想到的:这是一个case类,它是一个字段,是一个类,什么是类型参数,是抽象的等等。你可能不会查询任何可能依赖于当前词法范围的东西,例如一个班级有什么成员。您也可能无法以任何方式与您反思的内容进行交互(如访问字段或调用方法)。你可以查询元数据。

    一个班级的成员如何随词汇范围而变化?想象一下带有单个def foo: String的抽象类。名称foo可能在一个上下文中绑定到def(如果您查询它,则会给出MethodSymbol),或者可能在另一个上下文(给出TermSymbol)时将其绑定到val。当使用符号的工作是很常见明确必须声明你期待什么样的符号,你通过这些方法.asTerm.asMethod.asClass

    继续,我们开始与String例子做到这一点。您可以使用Mirror推导出描述类的ClassSymbolcurrentMirror.staticClass(myString)

  • Types:类型允许您查询有关符号在当前词汇上下文中引用的类型的信息。您通常使用Type来做两件事:查询哪些变量,vals和defs,以及查询类型关系(例如,此类型是该类型的子类)。有两种方法可以获得Type。通过TypeSymbolClassSymbolTypeSymbol)或通过TypeTag

    继续这个例子,你将调用.toType方法来得到Type的符号。

  • Scopes:当你问一个Type.members.decl - 这是什么让你条件(VAR和丘壑)和方法,你得到的Symbol S中的成员在当前词法范围的列表。此列表保存在MemberScope类型中,它只是一个荣耀的List[Symbol]

    在我们上面的抽象类的示例中,取决于当前范围,此列表将包含名称fooTermSymbolMethodSymbol

  • Names:名称有两种口味:TermNameTypeName。它只是一个String的包装。您可以使用该类型来确定由任何Name命名的内容。
  • Mirrors:最后镜子是你用来与“某物”交互的东西。您通常从Symbol开始,然后使用该符号为要与之交互的方法,构造函数或字段派生符号。当你有你需要的符号时,你使用currentMirror为这些符号创建镜像。通过镜像,您可以调用构造函数(ClassMirror),访问字段(FieldMirror)或调用方法(MethodMirror)。您不能使用镜像来查询关于所反映事物的元数据。

所以把一个例子一起反映上面的描述中,这是你如何将搜索领域,调用构造函数和阅读val,给出完全限定类名String

// Do runtime reflection on classes loaded by current ClassLoader 
val currentMirror: universe.Mirror = scala.reflect.runtime.currentMirror 

// Use symbols to navigate to pick out the methods and fields we want to invoke 
// Notice explicit symbol casting with the `.as*` methods. 
val classSymbol: universe.ClassSymbol = currentMirror.staticClass("com.example.Foo") 
val constructorSymbol: universe.MethodSymbol = classSymbol.primaryConstructor.asMethod 
val fooSymbol: Option[universe.TermSymbol] = classSymbol.toType.members.find(_.name.toString == "foo").map(_.asTerm) 

// Get mirrors for performing constructor and field invocations 
val classMirror: universe.ClassMirror = currentMirror.reflectClass(classSymbol) 
val fooInstance: Foo = classMirror.reflectConstructor(constructorSymbol).apply().asInstanceOf[Foo] 
val instanceMirror: universe.InstanceMirror = currentMirror.reflect(fooInstance) 

// Do the actual invocation 
val fooValue: String = instanceMirror.reflectField(fooSymbol.get).get.asInstanceOf[String] 
println(fooValue) // Prints the value of the val "foo" of the object "fooInstance"