我正在使用Scala 2.10.1,我正在尝试定义一个方法,该方法将从对象中检索所有val(包括继承的val)。
我有以下内容:
import scala.reflect.runtime.{universe => ru}
object Reflection {
val mirror = ru.runtimeMirror(this.getClass.getClassLoader)
def findVals(x: Any): Iterable[String] = {
val theType = mirror.classSymbol(x.getClass).toType
theType.members.collect({case x if x.isTerm => x.asTerm}).filter(_.isVal).map(_.name.toString)
}
}
我正在测试这两个类:
class Base {
val x = 10
}
class Child extends Base {
val y = 20
}
调用以下代码时:
val x = new Child
val vs = Reflection.findVals(x)
println(vs)
结果为List(y)
出于某种原因,isVal
方法会返回false
对应x
类中Base
字段的字词。
有人可以告诉我这里的问题是什么吗?我做错了吗?
答案 0 :(得分:4)
根据Why don't Scala case class fields reflect as public?,您应该使用isAccessor
代替isVal
。
我实际上正在使用isGetter
和setter
来根据您的评论正确过滤var
:
def findVals(x: Any): Iterable[String] = {
val theType = mirror.classSymbol(x.getClass).toType
val xtm = theType.members.collect({case x if x.isTerm => x.asTerm})
xtm.filter(m => m.isGetter && !xtm.exists(m.setter == _)).map(_.name.toString)
}
结果:
scala> class Base {
| var x = 10
| val xx = 2
| }
defined class Base
scala> class Child extends Base {
| val y = 3
| }
defined class Child
scala> val x = new Child
x: Child = Child@1c0026e
scala> val vs = Reflection.findVals(x)
vs: Iterable[String] = List(y, xx)
scala> println(vs)
List(y, xx)
答案 1 :(得分:2)
使用SMirror:
scala> implicit val mirror = scala.reflect.runtime.currentMirror
mirror: reflect.runtime.universe.Mirror = JavaMirror with scala.tool…
scala> import net.fwbrasil.smirror._
import net.fwbrasil.smirror._
scala> class Base {
val x = 10
}
defined class Base
scala> class Child extends Base {
val y = 20
}
defined class Child
scala> val x = new Child
x: Child = Child@448593d0
scala> x.reflect.vals
res5: List[net.fwbrasil.smirror.SInstanceVal[Child]] = List(val x: scala.Int (bound to Child@448593d0), val y: scala.Int (bound to Child@448593d0))
scala> x.reflect.vals.head.get
res7: Any = 10
答案 2 :(得分:0)
所以,这非常不优雅,但似乎有效:
import scala.reflect.runtime.{universe => ru}
object Reflection {
val mirror = ru.runtimeMirror(this.getClass.getClassLoader)
val ObjectClass = classOf[java.lang.Object];
def findVals(x: Any) : Iterable[String] = findVals( x.getClass, List.empty );
def findVals(clz: Class[_], accum : Iterable[String]): Iterable[String] = {
clz match {
case ObjectClass => accum;
case _ => {
val theType = mirror.classSymbol(clz).toType
val newVals = theType.members.collect({case x if x.isTerm => x.asTerm}).filter(_.isVal).map(_.name.toString)
findVals( clz.getSuperclass, accum ++ newVals )
}
}
}
}
则...
scala> class Base {
| val x = 10
| var z = 20
| }
defined class Base
scala> class Child extends Base {
| val y = 20
| var a = 9
| }
defined class Child
scala> val x = new Child
x: Child = Child@3093266d
scala> val vs = Reflection.findVals(x)
vs: Iterable[String] = List("y ", "x ")
scala> println(vs)
List(y , x )
似乎至少在目前,Scala reflection looks at the Java field确定了val的存在,所以我猜你只需要爬上类层次结构......我猜它看起来存在一个setter来区分val和var。再一次,不是那么可爱,但功能齐全。