Using Scala 2.10 reflection how can I list the values of Enumeration?

后端 未结 3 1843
别跟我提以往
别跟我提以往 2021-01-05 02:20

Having a following enumeration

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

How do I get a list of its vals?

相关标签:
3条回答
  • 2021-01-05 02:42

    The following code gets a list of Symbol objects representing the "vals":

    import reflect.runtime.universe._ // Access the reflection api
    
    typeOf[ResponseType.Value]  //  - A `Type`, the basic unit of reflection api
      .asInstanceOf[TypeRef]    //  - A specific kind of Type with knowledge of
                                //    the place it's being referred from
      .pre                      //  - AFAIK the referring Type
      .members                  //  - A list of `Symbol` objects representing
                                //    all members of this type, including 
                                //    private and inherited ones, classes and 
                                //    objects - everything.
                                //    `Symbol`s are the second basic unit of 
                                //    reflection api.
      .view                     //  - For lazy filtering
      .filter(_.isTerm)         //  - Leave only the symbols which extend the  
                                //    `TermSymbol` type. This is a very broad 
                                //    category of symbols, which besides values
                                //    includes methods, classes and even 
                                //    packages.
      .filterNot(_.isMethod)    //  - filter out the rest
      .filterNot(_.isModule)
      .filterNot(_.isClass)
      .toList                   //  - force the view into a final List
    

    It should be noted that instead of filtering on is-clauses it can be implemented with .collect testing for specific types, like so:

    .collect{ case symbol : MethodSymbol => symbol }
    

    This approach may be required for other tasks in the reflection api.

    It also should be noted, that using a .view is not mandatory at all, it just makes using a series of filter applications (as much as many other functions such as map, flatMap and etc.) much more effective, by traversing the input collection only once and at the point where it's actually being forced into some concrete collection (.toList in our case).

    Update

    As suggested by Travis Brown, it is also possible to reference the ResponseType object directly. So the typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre part can be replaced with typeOf[ResponseType.type]

    0 讨论(0)
  • 2021-01-05 02:47

    If you want to be thorough about this, you need to check that your symbols have Value as a supertype:

    def valueSymbols[E <: Enumeration: TypeTag] = {
      val valueType = typeOf[E#Value]
      typeOf[E].members.filter(sym => !sym.isMethod &&
        sym.typeSignature.baseType(valueType.typeSymbol) =:= valueType
      )
    }
    

    Now even if you have the following (which is perfectly legal):

    object ResponseType extends Enumeration {
      val Listing, Album = Value
      val someNonValueThing = "You don't want this in your list of value symbols!"
    }
    

    You still get the correct answer:

    scala> valueSymbols[ResponseType.type] foreach println
    value Album
    value Listing
    

    Your current approach would include value someNonValueThing here.

    0 讨论(0)
  • 2021-01-05 02:55

    You can iterate over the values of an enumeration via the set returned by the enumeration’s values method:

    scala> for (e <- ResponseType.values) println(e)
    Listing
    Album
    
    0 讨论(0)
提交回复
热议问题