关于Scala反射的简单问题:
- 我怎么能写一个方法
fields
返回某一类型的所有字段,甚至在子类? - 这是正确的做法吗?如果不是,你会怎么做?
的例子:
class Top { def fields = ... }
class A extends Top {
val f1 = Field(...)
val f2 = Field(...)
}
(new A).fields // List(f1, f2)
因此,在我的试验和错误中,我发现真正的运行时类型反射是困难的,因为当您要求隐式TypeTag时,Scala会在编译时嵌入类型信息。我发现,如果你想反映一个对象的类型,该对象的类型必须在编译时可用。(这可能反映了我的知识的限制,而不是Scala反射的限制,但我已经尝试过,到目前为止,没有反映出不能在编译时捕获的运行时类型。)
那么,这里是最接近你想要的,我知道怎么做的:
scala> import scala.reflect.runtime.universe._;
import scala.reflect.runtime.universe._
scala> class Base[T <: Base[T] : TypeTag] {
| def stringVals = typeOf[T].members.filter( _.isTerm ).map( _.asTerm).filter( _.isVal ).filter( _.typeSignature <:< typeOf[String] )
| }
defined class Base
scala> class Derived extends Base[Derived] {
| val f1 = "Bye";
| val f2 = 27;
| val f3 = "Sad.";
| }
defined class Derived
scala> (new Derived).stringVals
res0: Iterable[reflect.runtime.universe.TermSymbol] = List(value f3, value f1)
注意,在扩展Base时必须显式地命名自己的类型,以便在编译时可以嵌入适当的TypeTag(作为隐式嵌入到构造函数中)。我只是不知道如何解决这个问题。
这里的值以TermSymbols列表的形式返回。我不知道你想要什么;如果您只想要字符串val名称,请添加"。map(_.name.toString.trim)"到stringVals函数的末尾。(我发现调用trim在实践中很重要,但我打赌随着反射库的最终完成和发展,它将变得多余。)
祝你好运!