1

我确定它是重复的,但我找不到它。

考虑这个类

class Test1(var param: Int)

Scala 生成一个 getter 和一个 setter,并将参数设为私有。

它可以使用 javap 显示,例如:

public class Test1 {
  private int param;
  public int param();
  public void param_$eq(int);
  public Test(int);
}

我试图用显式的 getter / setter 编写它的脱糖版本,但不能 100% 这样做,因为私有 var 与 getter 发生命名冲突。

class Test2(private[this] var param:Int) {
  def param:Int = this.param
  def param_= (param:Int) {this.param = param}
}

这是错误:

ambiguous reference to overloaded definition,
both method param in class Test2 of type => Int
and  variable param in class Test2 of type Int
match expected type Int
  def param:Int = param
                  ^

这当然有效(将私人成员重命名为_param

class Test3(private[this] var _param:Int) {
  def param:Int = this._param
  def param_= (param:Int) {this._param = param}
}

但是当然会生成这个略有不同的字节码(因为我们必须重命名param_param):

public class Test3 {
  private int _param;
  public int param();
  public void param_$eq(int);
  public Test3(int);
}

Test1在使用显式 getter / setter 时,有什么方法可以达到与示例相同的字节码Test2

4

3 回答 3

4

在 Scala 中,方法和字段共享相同的名称空间。对于来自 Java 或其他语言的转换来说,这有点令人困惑,它们都有单独的名称空间。

但它遵循统一访问原则,即在没有括号使用时,类的用户无法判断他实际上是在调用 def 还是 val(或 var)。这也意味着您可以在 val 和 def 之间切换实现,而不会影响客户端。(我不确定他们是否必须重新编译,但源代码可以保持原样。

于 2013-07-10T05:07:26.823 回答
2

其实,你可以!

这是一个效果很好的答案。

在那里你会发现一个私有变量和一个同名的访问器。

private[this] var state
private final def state()

请注意访问器定义上的括号,在使用站点不需要这些括号。

在幕后,本地字段具有 LOCAL_SUFFIX_STRING,这是一个邪恶的空间。请参阅Test3下面的成员,它们剥去覆盖物以裸露所有。

在吸气剂方面,您可以添加括号。显然,这打破了糖精二传手。你能没有含糖的赋值语法吗?

当您引用x.param时,编译器将提供括号,请参阅@alexiv 在其他地方关于统一访问的评论或上面提到的 SO 答案。

  import reflect.runtime.currentMirror
  import reflect.runtime.universe._
  class Test2(private[this] var param: Int) {
    def param(): Int = param
    def param_=(param: Int) { this.param = param }
  }
  val x = new Test2(1)
  Console println x.param
  x.param_=(2)
  Console println x.param
  class Test3(var param: Int)
  val ps = typeOf[Test3].members filter (m => m.name.toString.startsWith("param")) map (m => s"'${m.name.toString}'")
  Console println ps
  Console println (typeOf[Test3].members filter (_.name.toString.endsWith(nme.LOCAL_SUFFIX_STRING)))

请注意,其他答案表明 Scala 仅区分术语和类型,而忽略了符号(显然)可以重载。

您可能已经读过重载是邪恶的!可能是这样,但无论您在自己的私人成员的隐私中做什么,都完全是您自己的事。

(更新以表明即使问题在某处有些重复,这仍然是一个有趣且内容丰富的答案。)

于 2013-07-10T05:54:55.667 回答
0

我认为变量和方法是一样的,变量param就像一个没有参数的方法,方法param是一样的,所以就像错误指示:对重载定义的模糊引用。

于 2013-07-10T05:02:12.230 回答