构造函数参数名称和类成员名称

时间:2014-06-27 10:10:57

标签: scala

我通常理解Scala如何处理构造函数参数,即 为val生成getter,为var生成getter / setter。 我也发现了很多关于名字冲突的讨论 构造函数参数和类成员。

对于没有val&的名字var,我希望如果他们以this.为前缀,那么类成员应该这样做 使用。但事实并非如此。

class A(val a: Int) {
  def m = println("A.a: " + a)
}

class B(a: Int) extends A(2 * a) {
  override def m = {
    super.m
    println("@a: " + a)
    println("this.a: " + this.a)  // this is @a, not A.a
  }
}

object TestApp extends App {
    val b = new B(10)
    b.m
    println(b.a); // this is A.a
}

输出:

A.a: 20
@a: 10
this.a: 10
20

我觉得它有些奇怪,但背后有设计理由吗?

1 个答案:

答案 0 :(得分:2)

正如您在问题中写的那样,Scala会为val生成一个getter,因此当您在val类中声明A参数时,它实际上有一个方法{{1} }和一个字段m,由a类继承。但是你在B类中也有一个a参数,它被加倍并作为参数传递给B的超级构造函数。要了解正在进行的操作,请为您的代表打开选项A并粘贴代码,例如-Xprint:typer代表如下:

A

正如您所见,Scala为您class A extends scala.AnyRef { <paramaccessor> private[this] val a: Int = _; <stable> <accessor> <paramaccessor> def a: Int = A.this.a; def <init>(a: Int): A = { A.super.<init>(); () }; def m: Unit = scala.this.Predef.println("A.a: ".+(A.this.a)) } 参数创建了一个隐藏的private[this]字段。这里是a类的表示:

B

正如您所见,Scala还为class B extends A { <paramaccessor> private[this] val a: Int = _; def <init>(a: Int): B = { B.super.<init>(2.*(a)); () }; override def m: Unit = { B.super.m; println("@a: ".+(B.this.a)); println("this.a: ".+(this.a)) } } 类中的private[this]参数定义了a字段。但是因为你没有将它标记为B值,所以它没有生成新的val getter,它仍被定义为a,但不是A.this.a这就是为什么你在调用B.this.a时获得20的原因。

作为答案,我不认为这背后有一些复杂的设计,它看起来合乎逻辑且非常合理。如果您在b.a类构造函数中重命名a参数并将其传递给B,则不会发生任何变化。