【发布时间】:2014-01-08 16:06:28
【问题描述】:
Scala 类中的vars 自动获取 getter 和 setter,您可以通过 members 的 scala 反射看到
import scala.reflect.runtime.{universe => ru}
class A(var x: Int)
scala> ru.typeOf[A].members.filter{_.name.toString.contains("x")}
res22: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(variable x, method x_=, method x)
但是,如果您创建一个子类,它在构造函数中重用 var 名称,getter 就消失了:
class B(x:Int, var y: Int) extends A(x)
scala> ru.typeOf[B].members.filter{_.name.toString.contains("x")}
res23: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value x, method x_=)
scala> res23.head.asTerm.isVal
res25: Boolean = true
这似乎有点误导......毕竟,B 仍然有 x 的吸气剂(而不是 val)
scala> val b = new B(5,6)
b: B = B@270288ed
scala> b.x
res26: Int = 5
scala> b.x = 7
b.x: Int = 7
scala> b.x
res27: Int = 7
如果我试图假装从members 得到的value x 是一个getter,我会得到一个错误:
scala> val xGetter = res23.head.asTerm
xGetter: reflect.runtime.universe.TermSymbol = value x
scala> val objMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(b)
objMirror: reflect.runtime.universe.InstanceMirror = instance mirror for B@270288ed
scala> val getterMirror = objMirror.reflectField(xGetter)
scala.ScalaReflectionException: Scala field x isn't represented as a Java field, neither it has a Java accessor method
note that private parameters of class constructors don't get mapped onto fields and/or accessors,
unless they are used outside of their declaring constructors.
什么是正确的解决方法?将子类名称及其构造函数参数与父参数中的名称相同是完全错误的吗?或者我不需要调用 members,而是需要对所有超类进行处理以获取所有 getter 和 setter?
请注意,只要子类不创建具有相同名称的构造函数,members 就会为我提供继承的 getter:
class Y(var x: Int)
class Z(q:Int, z: Int) extends Y(q)
scala> ru.typeOf[Z].members.filter{_.name.toString.contains("x")}
res28: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method x_=, method x)
编辑
如果不清楚,我真的在问:
1)这是scala反射中的错误吗?
2)如果没有,我应该:
(a) 从来没有类使用构造函数字段的名称与基类中的字段名称相同? (如果是这样,我可能把我所有的类都定义错了......)
要么
(b) 要获取所有 getter 和 setter,我是否应该浏览所有父类的列表并使用 declarations,而不是依靠 members 做正确的事情,因为在这种情况下它不起作用?
编辑 2
响应@som-snytt 的回答,x 的可见方法实际上在A 中的x 上,而不是B 的构造函数中的参数。例如:
class A(var x: Int){def showMeX {println(x)}}
class B(x:Int, var y: Int) extends A(x)
scala> val b = new B(5,10)
scala> b.showMeX
5
scala> b.x = 17
b.x: Int = 17
scala> b.showMeX
17
所以从普通用户代码的角度来看,我真的不认为x 的getter 或setter 已被隐藏。它仅被反射代码遮蔽......对我来说,有两种不同版本的遮蔽是没有意义的。
【问题讨论】:
-
这似乎是一个错误,请报告它here,可以肯定地告诉它。
-
感谢@sschaef,在此报告issues.scala-lang.org/browse/SI-8096
-
@som-snytt ha,是的,我已经潜伏了很长时间,只是变得活跃......
标签: scala reflection