#scala
#scala
Вопрос:
В целом я понимаю, как Scala работает с параметрами конструктора, то есть генерирует getter для val и getter / setter для var. Я также нашел довольно много обсуждений о столкновениях имен между параметрами конструктора и членами класса.
Для этих имен без val amp; 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:
Как вы написали в своем вопросе, Scala генерирует геттер для a val
, поэтому, когда вы объявляете val
параметр в A
своем классе, у него фактически есть метод m
и поле a
, которые наследуются B
классом. Но у вас также есть a
параметр в вашем B
классе, который удваивается и передается в качестве аргумента суперконструктору A
. Чтобы понять, что происходит, включите опцию -Xprint:typer
для вашего репозитория и вставьте свой код, например A
, представленный следующим образом:
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))
}
Как вы можете видеть, Scala создала скрытое private[this]
поле для вашего a
параметра. И вот представление для B
класса:
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))
}
}
Как вы можете видеть, Scala также определила private[this]
поле для вашего a
параметра в B
классе. Но поскольку вы не пометили его как val
значение, он не сгенерировал новый a
геттер, который по -прежнему определяется как A.this.a
, но не B.this.a
, поэтому вы получаете r 20
при вызове b.a
.
В качестве ответа я не думаю, что за этим стоит какой-то сложный дизайн, он выглядит логичным и вполне разумным. Если вы переименуете свой a
параметр в B
конструкторе класса и передадите его A
, ничего не изменится.