在Scala Reflection中,为什么构造函数params会隐藏getter?

 Tong-david 发布于 2023-02-09 09:28

varscala类中的s会自动获取getter和setter,你可以通过scala反射来看到 members

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(而不是a 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

如果我试图假装value x我来自members一个吸气剂,我会收到一个错误:

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.

这里有什么正确的解决方法?具有子类名称,其构造函数args与父args中的名称相同是完全错误的吗?或者不是打电话members,我是否需要努力学习所有超级课程以获得所有的乐趣和制定者?

注意,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确实xA,而不是构造函数中的参数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 都被遮蔽了.它只被反射代码遮蔽了......对我来说没有任何意义,它会有两种不同版本的阴影.

1 个回答
  • 2)如果没有,我应该:(a)从来没有类使用构造函数字段的名称与基类中的字段名称相同?

    因为他们不会让我解决这个问题,这正是我所做的.我尝试给所有构造函数参数赋予与所有继承名称不同的新名称.这是编译器中的典型示例.

    class PackageClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TypeName)
    

    是的,这太荒谬了.

    https://groups.google.com/forum/#!topic/scala-language/9jLsT_RRQR0

    https://issues.scala-lang.org/browse/SI-3194

    https://issues.scala-lang.org/browse/SI-4762

    https://issues.scala-lang.org/browse/SI-6880

    哦,小伙子,不要继续拉那个线程......

    https://issues.scala-lang.org/browse/SI-7475

    https://issues.scala-lang.org/browse/SI-2568

    https://issues.scala-lang.org/browse/SI-6794

    不难看出任何一个被解决的几率为零.这是我退出原因的一个完美例子.

    顺便说一句,如果你使用-Xlint,它就会警告你.这在SI-4762中提到过.

    % cat a.scala
    class A(var x: Int)
    class B(x:Int, var y: Int) extends A(x) {
      def z = x
    }
    
    % scalac -Xlint a.scala
    a.scala:3: warning: private[this] value x in class B shadows mutable x inherited from class A.
    Changes to x will not be visible within class B - you may want to give them distinct names.
      def z = x
              ^
    one warning found
    

    2023-02-09 09:31 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有