2

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

  • 我如何编写一个方法fields来返回某种类型的所有字段,即使是在子类中?
  • 这甚至是正确的方法吗?如果不是,你会怎么做?

例子 :

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

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

1 回答 1

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(作为我的构造函数中的隐含)。我只是不知道解决办法。

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

祝你好运!

于 2013-04-03T11:14:34.670 回答