我通常理解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
我觉得它有些奇怪,但背后有设计理由吗?
答案 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
,则不会发生任何变化。