2016-07-25 8 views
1

Ich möchte Scala-Enumerationskonstanten nach Namen abrufen.Abrufen von Scala-Enumerationskonstanten nach Name

Dmitriy Yefremov eine Lösung mit Scala 2,10 (@see http://yefremov.net/blog/scala-enum-by-name/)

Der Code Absturz mit

private def factoryMethodSymbol(enumType: Type): MethodSymbol = { 
    enumType.member(newTermName("withName")).asMethod // scala.ScalaReflectionException: <none> is not a method 
} 

schlage ich möchte diesen Code aktualisieren Scala verwenden 2.11. Irgendeine Idee?

+0

Der Blog-Code funktioniert für mich nur Einfügen in REPL. Du musst deine Arbeit zeigen. –

+0

@ user1875107: Übergeben Sie 'classOf [MyEnum.Value]' (schlecht) anstelle von 'classOf [MyEnum.type]' oder 'MyEnum.getClass' (gut) zufällig? –

Antwort

2

Sie können dies bereits mit der bestehenden API tun, brauchen Sie nicht die Abhilfen:

def constantByName[T <: Enumeration](enum: T, key: String): Option[T#Value] = { 
    enum.values.find(_.toString == key) 
} 

Es funktioniert, weil .values gibt Ihnen eine List[Enum#Value] und Sie können nur für die Anpassung in diesem Blick.

+0

Ich möchte diese Verwendung: constantByName (t.getClass, Schlüssel). –

0

Die Lösung lautet:

def constantByName(clazz: Class[_],value:String):Enumeration#Value = 
{ 
    val module=mirror.reflectModule(
    mirror.classSymbol(clazz) 
    .toType.typeSymbol.companion.asModule) 
    .instance.asInstanceOf[Enumeration] 
    module.values.find(_.toString == value).get 
} 
1

Reflexion bekannt Probleme mit dem Symbol init haben und es fehlt auch die Thread-Sicherheit. Vielleicht löst man so das Symptom aus.

angezeigt, dass der ursprüngliche Code funktioniert:

$ scala 
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92). 
Type in expressions for evaluation. Or try :help. 

scala> object FunninessLevel extends Enumeration { 
    | type FunninessLevel = Value 
    | val LOL, ROFL, LMAO = Value 
    | } 
defined object FunninessLevel 

scala> 

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

import scala.reflect.runtime.universe._ 

/** 
* Scala [[Enumeration]] helpers implementing Scala versions of 
* Java's [[java.lang.Enum.valueOf(Class[Enum], String)]]. 
* @author Dmitriy Yefremov 
*/ 
object EnumReflector { 

    private val mirror: Mirror = runtimeMirror(getClass.getClassLoader) 

    /** 
    * Returns a value of the specified enumeration with the given name. 
    * @param name value name 
    * @tparam T enumeration type 
    * @return enumeration value, see [[scala.Enumeration.withName(String)]] 
    */ 
    def withName[T <: Enumeration#Value: TypeTag](name: String): T = { 
    typeOf[T] match { 
     case valueType @ TypeRef(enumType, _, _) => 
     val methodSymbol = factoryMethodSymbol(enumType) 
     val moduleSymbol = enumType.termSymbol.asModule 
     reflect(moduleSymbol, methodSymbol)(name).asInstanceOf[T] 
    } 
    } 

    /** 
    * Returns a value of the specified enumeration with the given name. 
    * @param clazz enumeration class 
    * @param name value name 
    * @return enumeration value, see [[scala.Enumeration#withName(String)]] 
    */ 
    def withName(clazz: Class[_], name: String): Enumeration#Value = { 
    val classSymbol = mirror.classSymbol(clazz) 
    val methodSymbol = factoryMethodSymbol(classSymbol.toType) 
    val moduleSymbol = classSymbol.companionSymbol.asModule 
    reflect(moduleSymbol, methodSymbol)(name).asInstanceOf[Enumeration#Value] 
    } 

    private def factoryMethodSymbol(enumType: Type): MethodSymbol = { 
    enumType.member(newTermName("withName")).asMethod 
    } 

    private def reflect(module: ModuleSymbol, method: MethodSymbol)(args: Any*): Any = { 
    val moduleMirror = mirror.reflectModule(module) 
    val instanceMirror = mirror.reflect(moduleMirror.instance) 
    instanceMirror.reflectMethod(method)(args:_*) 
    } 

} 


// Exiting paste mode, now interpreting. 

warning: there were two deprecation warnings; re-run with -deprecation for details 
import scala.reflect.runtime.universe._ 
defined object EnumReflector 

scala> val level = EnumReflector.withName(FunninessLevel.getClass, "ROFL") 
level: Enumeration#Value = ROFL 

die REPL Kräfte Initialisierung durch Zufall manchmal. Die Befehlszeile wird angezeigt: