2016-07-25 78 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