0

我正在使用 Scala 2.10.1,我正在尝试定义一个方法,该方法将从对象中检索所有 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对应的术语。xBase

有人可以告诉我这里有什么问题吗?难道我做错了什么?

4

3 回答 3

4

Per为什么 Scala 案例类字段不反映为公共的?你应该使用isAccessor而不是isVal.

我实际上正在使用isGetter并根据您的评论setter正确过滤s: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)
于 2013-04-03T14:14:32.757 回答
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
于 2013-04-03T19:04:14.870 回答
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 反射查看 Java 字段以确定 val 的存在,所以我猜你只需要爬上类层次结构......我猜它会寻找 setter 的存在区分 val 和 var。再次,不是那么可爱,但功能齐全。

于 2013-04-03T15:55:20.053 回答