我想按名称检索scala枚举常量。
Dmitriy Yefremov提出了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 :(得分:2)
您已经可以使用现有API执行此操作,您不需要解决方法:
def constantByName[T <: Enumeration](enum: T, key: String): Option[T#Value] = {
enum.values.find(_.toString == key)
}
它有效,因为.values
会为您提供List[Enum#Value]
,您可以查看匹配的内容。
答案 1 :(得分: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
答案 2 :(得分: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
}