Domanda

Having a following enumeration

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

How do I get a list of its vals?

È stato utile?

Soluzione

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.

Altri suggerimenti

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]

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top