无法通过 Scala 反射获得继承的 vals



我正在使用Scala 2.10.1,我正在尝试定义一个方法,它将从对象中检索所有的值(包括继承的值)。

我有以下内容:

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方法为Base类的x字段对应的项返回false

谁能告诉我这里有什么问题?我做错了什么吗?

Per为什么Scala的case类字段不反映为public?你应该使用isAccessor而不是isVal

我实际上使用isGettersetter来正确过滤var s根据您的评论:

  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)

Using mirror:

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

所以,这是非常不优雅的,但它似乎工作:

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反射查看Java字段来确定val的存在,所以我猜你只需要爬上类层次结构…我猜它会寻找setter的存在来区分val和var,同样,不是很可爱,但是很实用。

相关内容

  • 没有找到相关文章