枚举Scala中子类的字段

时间:2013-04-03 10:00:58

标签: scala reflection

关于Scala中反射的简单问题:

  • 如何编写返回特定类型所有字段的方法fields,即使在子类中也是如此?
  • 这是否是正确的方法呢?如果不是,你会怎么做?

示例:

class Top { def fields = ... }
class A extends Top {
  val f1 = Field(...)
  val f2 = Field(...)
}

(new A).fields // List(f1, f2)

1 个答案:

答案 0 :(得分:4)

因此,在我的试验和错误中,我发现真正的运行时类型反射很困难,因为Scala在编译时要求隐式TypeTag时嵌入类型信息的技巧。我发现,如果你想反思一个对象的类型,那么该对象的类型必须在编译时可用。 (这可能反映了我的知识限制,而不是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(作为隐式到我的构造函数中)。我只是不知道如何解决这个问题。

这些val以TermSymbols列表的形式返回。我不确定你想要什么;如果您只想要String val名称,请将“.map(_. name.toString.trim)”添加到stringVals函数的末尾。 (我发现修剪的调用在实践中很重要,但我敢打赌,随着反射库的最终确定和发展,它将变得多余。)

祝你好运!