2016-07-25 7 views
1

名前でスカラー列挙定数を取得したいと思います。名前でスカラ列挙定数を取得する

ドミトリYefremov私はスカラ2.11を使用するには、このコードを更新したいスカラ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 
} 

有するコードクラッシュの溶液を提案します。

+0

ブログコードはREPLに貼り付けるだけで動作します。あなたはあなたの仕事を示す必要があります。 –

+0

@ user1875107:万が一 'classOf [MyEnum.type]'や 'MyEnum.getClass'(good)の代わりに' classOf [MyEnum.Value] '(悪い)を渡していますか? –

答えて

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 
関連する問題