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

时间:2017-10-19 01:28:21

标签: scala reflection types symbols mirror

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

1 个答案:

答案 0 :(得分:9)

使用Scala Reflection API时,如果您使用了Java Reflection API,那么您会遇到更多类型的内容。给出一个示例场景,您可以从包含类的完全限定类名的String开始,这些是您可能遇到的类型:

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

    与Java一样,您通常会选择要反映的ClassLoader类,从而开始任何反思。 Scala提供了使用当前类的ClassLoader的快捷方式:scala.reflect.runtime.currentMirror,这会为您提供Mirror(稍后会在镜像上提供更多信息)。许多JVM应用程序只使用一个类加载器,因此这是Scala Reflection API的常见入口点。由于您正在从runtime导入,现在您已进入该Universe。

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

    词汇范围是你能做的一切"见"在您正在进行反思的地方,不包括隐式范围(有关不同范围的处理,请参阅this SO)。一个班级的成员如何根据词汇范围而变化?想象一下具有单个def foo: String的抽象类。名称foo可能在一个上下文中绑定到def(如果您查询它,则会为您提供MethodSymbol),或者可能绑定到另一个上下文中的val (给你一个TermSymbol)。使用符号时,明确必须说明您期望的符号类型,通过方法.asTerm.asMethod.asClass等来实现这一点。

    继续我们开始的String示例。您使用Mirror派生了一个描述该类的ClassSymbolcurrentMirror.staticClass(myString)

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

    继续该示例,您将在您获得.toType的符号上调用Type方法。

  • Scopes :当您向Type询问.members.decl时,这就是为您提供的条款(vars和vals)和方法 - 你得到当前词法范围内Symbol成员的列表。此列表保存在MemberScope类型中,它只是一个荣耀的List[Symbol]

    在我们上面使用抽象类的示例中,根据当前范围,此列表将包含名称TermSymbol的{​​{1}}或MethodSymbol

  • Names :名称分为两种:fooTermName。它只是TypeName的包装。您可以使用该类型来确定任何String命名的内容。
  • Mirrors :最后镜像是你用来与#34;东西"进行交互的东西。您通常从Name开始,然后使用该符号为您想要与之交互的方法,构造函数或字段派生符号。如果您有所需的符号,则使用Symbol为这些符号创建镜像。 Mirrors允许您调用构造函数(currentMirror),访问字段(ClassMirror)或调用方法(FieldMirror)。您可能无法使用镜像来查询有关所反映事物的元数据。

因此,将一个示例放在一起反映上面的描述,这就是在给定带有完全限定类名的MethodMirror的情况下搜索字段,调用构造函数和读取val的方法:

String