2016-07-25 79 views
1

我想按名稱檢索scala枚舉常量。按名稱檢索Scala枚舉常量

德米特里葉夫列莫夫建議使用Scala 2.10(@see http://yefremov.net/blog/scala-enum-by-name/

代碼崩潰的解決方案與

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

我想更新該代碼使用的Scala 2.11。 有什麼想法?

+0

博客代碼適用於我剛粘貼到REPL。你必須展示你的工作。 –

+0

@ user1875107:你是否通過'classOf [MyEnum.Value]'(壞)而不是'classOf [MyEnum.type]'或者'MyEnum.getClass'(good)? –

回答

2

您已經可以與現有的API做到這一點,你不需要解決方法:

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

它的工作原理,因爲.values給你一個List[Enum#Value]並且你可以調查一下匹配。

+0

我想這個用法:constantByName(t.getClass,key)。 –

0

解決的辦法是:

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

反思是已知有符號的init問題,也缺乏線程安全的。也許這就是你如何引發症狀。

顯示,原來的代碼工作:意外

$ 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 

有時REPL力量初始化。顯示命令行:

$ scalac reflect-enum.scala && scala reflect_enum.Test 
reflect-enum.scala:45: warning: method companionSymbol in trait SymbolApi is deprecated: Use `companion` instead, but beware of possible changes in behavior 
    val moduleSymbol = classSymbol.companionSymbol.asModule 
           ^
reflect-enum.scala:50: warning: method newTermName in trait Names is deprecated: Use TermName instead 
    enumType.member(newTermName("withName")).asMethod 
        ^
two warnings found 
ROFL