我正在处理一些使用自定义枚举的代码,以确保完整性检查,并且需要使用反射来获取可能的值列表。像下面这样的一些代码已经存在于代码库中(所有不相关的代码都被删除和/或重命名)我将它们组合成一个独立的可运行格式。
import scala.reflect.runtime.universe.TypeTag
object ReflectionUtil {
def modules[A : TypeTag](parent: Any) = {
import scala.reflect.runtime.{currentMirror, universe}
val members = currentMirror.classSymbol(parent.getClass).toType.members
.filter{ symbol =>
println(s"$symbol: ${symbol.typeSignature} <:< ${universe.typeOf[A]} is ${symbol.typeSignature <:< universe.typeOf[A]}")
symbol.typeSignature <:< universe.typeOf[A]
}
}
}
trait Enumeration {
type Value <: V
protected[this] trait V
lazy val values = ReflectionUtil.modules[V](this)
}
object Switch extends Enumeration {
sealed trait Value extends V
case object On extends Value
case object Off extends Value
}
object Main {
def main(args: Array[String]) = println(Switch.values)
}
这里的问题是行symbol.typeSignature <:< universe.typeOf[A]
,它会为出现的所有内容返回false,您可以在输出中看到:
object Off: Switch.Off.type <:< Enumeration.this.V is false
object On: Switch.On.type <:< Enumeration.this.V is false
constructor Switch: ()Switch.type <:< Enumeration.this.V is false
value values: => scala.Unit <:< Enumeration.this.V is false
trait V: scala.AnyRef {
} <:< Enumeration.this.V is false
method $init$: ()scala.Unit <:< Enumeration.this.V is false
method $asInstanceOf: [T0]()T0 <:< Enumeration.this.V is false
method $isInstanceOf: [T0]()Boolean <:< Enumeration.this.V is false
method synchronized: [T0](x$1: T0)T0 <:< Enumeration.this.V is false
method ##: ()Int <:< Enumeration.this.V is false
method !=: (x$1: Any)Boolean <:< Enumeration.this.V is false
method ==: (x$1: Any)Boolean <:< Enumeration.this.V is false
method ne: (x$1: AnyRef)Boolean <:< Enumeration.this.V is false
method eq: (x$1: AnyRef)Boolean <:< Enumeration.this.V is false
method notifyAll: ()Unit <:< Enumeration.this.V is false
method notify: ()Unit <:< Enumeration.this.V is false
method clone: ()java.lang.Object <:< Enumeration.this.V is false
method getClass: ()java.lang.Class[_] <:< Enumeration.this.V is false
method hashCode: ()Int <:< Enumeration.this.V is false
method toString: ()java.lang.String <:< Enumeration.this.V is false
method equals: (x$1: Any)Boolean <:< Enumeration.this.V is false
method wait: ()Unit <:< Enumeration.this.V is false
method wait: (x$1: Long)Unit <:< Enumeration.this.V is false
method wait: (x$1: Long, x$2: Int)Unit <:< Enumeration.this.V is false
method finalize: ()Unit <:< Enumeration.this.V is false
method asInstanceOf: [T0]=> T0 <:< Enumeration.this.V is false
method isInstanceOf: [T0]=> Boolean <:< Enumeration.this.V is false
()
注意输出的前两行。 为什么即使对于看起来应该符合的类型(我真正感兴趣的枚举类型)以及我该如何解决这个问题,它总是会变回错误?
重申:我希望从lazy val values
得到的是On
中相关的枚举案例对象Off
和Switch
,这需要自动化以便它可以使用许多其他类似的枚举类型。
答案 0 :(得分:0)
为了后代,我会回答我自己的问题。
这是按预期工作的代码:
import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
object ReflectionUtil {
def modules[A : TypeTag](parent: Any): Iterable[A] = {
val baseType = typeOf[A]
for {
symbol <- currentMirror.classSymbol(parent.getClass).toType.members
if symbol.isModule && symbol.info.widen <:< baseType
} yield currentMirror.reflectModule(symbol.asModule).instance.asInstanceOf[A]
}
}
trait EnumeratedValue
trait Enumeration {
type Value <: EnumeratedValue
lazy val values = ReflectionUtil.modules[EnumeratedValue](this)
}
object Switch extends Enumeration {
sealed trait Value extends EnumeratedValue
case object On extends Value
case object Off extends Value
}
object Main {
def main(args: Array[String]) = println(Switch.values)
}
事实证明,由于traits嵌入到生成的类字节码中,因此所有使用外部特征的类的内部特征都不相同。因此,它检查是否符合与函数定义中实际传递的特性不同的特征。通过拉出相关特征超出Enumeration
特征,该函数现在可以正确地解析特征,因此它可以按预期工作。