我写了一些使用反射的Scala代码,它返回某个类型对象中的所有val。以下是这个代码的三个版本。其中一个工程,但很丑。以两种不同的方式尝试改进它并不起作用。你能解释为什么吗?斯卡拉反思难题:你能解释这些奇怪的结果吗?
首先,代码:
import scala.reflect.runtime._
import scala.util.Try
trait ScopeBase[T] {
// this version tries to generalize the type. The only difference
// from the working version is [T] instead of [String]
def enumerateBase[S: universe.TypeTag]: Seq[T] = {
val mirror = currentMirror.reflect(this)
universe.typeOf[S].decls.map {
decl => Try(mirror.reflectField(decl.asMethod).get.asInstanceOf[T])
}.filter(_.isSuccess).map(_.get).filter(_ != null).toSeq
}
}
trait ScopeString extends ScopeBase[String] {
// This version works but requires passing the val type
// (String, in this example) explicitly. I don't want to
// duplicate the code for different val types.
def enumerate[S: universe.TypeTag]: Seq[String] = {
val mirror = currentMirror.reflect(this)
universe.typeOf[S].decls.map {
decl => Try(mirror.reflectField(decl.asMethod).get.asInstanceOf[String])
}.filter(_.isSuccess).map(_.get).filter(_ != null).toSeq
}
// This version tries to avoid passing the object's type
// as the [S] type parameter. After all, the method is called
// on the object itself; so why pass the type?
def enumerateThis: Seq[String] = {
val mirror = currentMirror.reflect(this)
universe.typeOf[this.type].decls.map {
decl => Try(mirror.reflectField(decl.asMethod).get.asInstanceOf[String])
}.filter(_.isSuccess).map(_.get).filter(_ != null).toSeq
}
}
// The working example
object Test1 extends ScopeString {
val IntField: Int = 13
val StringField: String = "test"
lazy val fields = enumerate[Test1.type]
}
// This shows how the attempt to generalize the type doesn't work
object Test2 extends ScopeString {
val IntField: Int = 13
val StringField: String = "test"
lazy val fields = enumerateBase[Test2.type]
}
// This shows how the attempt to drop the object's type doesn't work
object Test3 extends ScopeString {
val IntField: Int = 13
val StringField: String = "test"
lazy val fields = enumerateThis
}
val test1 = Test1.fields // List(test)
val test2 = Test2.fields // List(13, test)
val test3 = Test3.fields // List()
的 “枚举” 方法确实可行。但是,从Test1示例中可以看到,它需要将对象自己的类型(Test1.type)作为参数传递,这不应该是必需的。 “enumerateThis”方法试图避免,但失败,产生一个空列表。 “enumerateBase”方法试图通过传递val类型作为参数来概括“枚举”代码。但它也失败了,产生了所有瓦尔的列表,而不仅仅是某种类型的列表。
任何想法是怎么回事?
您是否尝试反编译类文件?这通常可以解释这些问题。 – bwawok 2014-11-06 19:07:34
是的,我做到了。以上是裸骨的例子。原来有不同的文件甚至包的类。 – silverberry 2014-11-06 19:13:40