如何获得 Scala 2.10 反射引用的实际对象? [英] How can I get the actual object referred to by Scala 2.10 reflection?

查看:36
本文介绍了如何获得 Scala 2.10 反射引用的实际对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑此代码:

object ResponseType extends Enumeration {
  val Listing, Album = Value
}

我可以像这样得到引用这个对象的Symbol:

I can get the Symbol referring to this object like so:

import reflect.runtime.universe._
val s = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol

现在,有了这个符号,我怎样才能获得实际的 ResponseType 对象?

Now, having this symbol, how can I get the actual ResponseType object?

推荐答案

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 中抽象出来.

Now, some explanation is in order, since this is quite an obscure implementation detail we've (yet!) been unable to abstract over in the public API.

对于每个object,Scala 会创建一个表示其签名的底层类,内部称为模块类.例如,如果您编译object C,编译器将生成C$.class.这正是模块类.

For every object Scala creates an underlying class that represents its signature, internally called module class. For example, if you compile object C the compiler will generate C$.class. That's exactly the module class.

请注意,模块类与伴随类不同.比如说,对于case class C,编译器会生成三个符号:type Cterm C和(另一个)type C,其中第一个 type C 代表 C 类(包含自动生成的副本、productPrefix、productArity 等),第二个 type C 代表 C 类的签名对象 C(包含自动生成的工厂、提取器等).不会有任何名称冲突,因为模块类不会直接添加到符号表中,只能通过 .moduleClass.

Note that module classes are different from companion classes. Say, for case class C, the compiler will generate three symbols: type C, term C and (another one) type C, where the first type C represents the class C (which contains auto-generated copy, productPrefix, productArity etc) and the second type C represents a signature of object C (which contains auto-generated factory, extractor etc). There won't be any name clashes, because the module class isn't added to the symbol table directly and is only available through <module>.moduleClass.

所以你实际上从你的 typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol 咒语中得到的是一个代表模块类的符号.API 中没有任何函数可以让您从模块类中获取模块符号.在编译器内部肯定有一个,但我们决定不公开这个实现细节,因为它很可能很快就会改变.

So what you actually get from your typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol incantation is a symbol that stands for a module class. There's no function in the API that would get you to a module symbol from a module class. Internally in the compiler there surely is one, but we decided not to expose this implementation detail, because it might very well change soon.

要访问源模块,您需要转到 owner,查看其成员列表并在那里查找与模块类具有相同名称的对象.这正是 moduleClass.owner.typeSignature.member(moduleClass.name.toTermName) 所做的.一个小警告是,如果在同一范围内您有一个同名的方法,那么 member 将返回一个重载符号,您需要执行类似 .member(...).suchThat(_.isModule).

To get to a source module you need to go to owner, peek into the list of its members and look up an object there having the same name as the module class has. That's exactly what moduleClass.owner.typeSignature.member(moduleClass.name.toTermName) does. One minor caveat is that if in the same scope you have a method with the same name, then member will return an overloaded symbol, and you'll need to do something like .member(...).suchThat(_.isModule).

之后就是小菜一碟了.

编辑.实际上,我们正在考虑引入 ClassSymbol.module ,它会返回模块类的源模块符号,否则返回 NoSymbol.很可能这将在 RC1 中结束.遵循发行说明.

Edit. Actually we're thinking of introducing ClassSymbol.module that would return source module symbol for a module class and NoSymbol otherwise. Quite probably this will end up in RC1. Follow the release notes.

这篇关于如何获得 Scala 2.10 反射引用的实际对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆