scala> val moduleClass = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol
moduleClass: reflect.runtime.universe.Symbol = object ResponseType
scala> val module = moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)
module: reflect.runtime.universe.Symbol = object ResponseType
scala> reflect.runtime.currentMirror.reflectModule(module.asModule).instance
res9: Any = ResponseType
现在,一些解释是有序的,因为这是一个相当模糊的实现细节,我们(还!)无法在公共 API 中抽象出来。
为每个object
Scala 创建一个代表其签名的底层类,内部称为模块类。例如,如果你编译编译object C
器会生成C$.class
. 这正是模块类。
请注意,模块类与伴随类不同。比如说,对于case class C
,编译器会生成三个符号:type C
和term C
(another one) type C
,其中第一个type C
代表 C 类(包含自动生成的副本、productPrefix、productArity 等),第二个type C
代表对象 C 的签名(包含自动生成的工厂、提取器等)。不会有任何名称冲突,因为模块类没有直接添加到符号表中,只能通过<module>.moduleClass
.
所以你实际上从你的typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol
咒语中得到的是一个代表模块类的符号。API 中没有任何函数可以让您从模块类中获取模块符号。在编译器内部肯定有一个,但我们决定不公开这个实现细节,因为它很可能很快就会改变。
要访问源模块,您需要转到owner
,查看其成员列表并在其中查找与模块类具有相同名称的对象。这正是这样moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)
做的。一个小警告是,如果在同一范围内您有一个具有相同名称的方法,那么member
将返回一个重载符号,您需要执行类似.member(...).suchThat(_.isModule)
.
之后就是小菜一碟了。
编辑。实际上,我们正在考虑引入ClassSymbol.module
它将返回模块类的源模块符号,否则返回 NoSymbol。很可能这最终会出现在 RC1 中。遵循发行说明。