How can I get the actual object referred to by Scala 2.10 reflection?

前端 未结 1 1604
再見小時候
再見小時候 2021-01-02 05:05

Please consider this code:

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

I can get the Symbol refer

相关标签:
1条回答
  • 2021-01-02 05:49
    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
    

    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.

    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.

    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.


    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.

    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).

    After that it's a piece of cake.


    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.

    0 讨论(0)
提交回复
热议问题