Ваша проблема не в имени типа self (во всех ваших примерах и this
, и альтернативное имя типа self относятся к одной и той же вещи и имеют один и тот же тип, а именно 'наибольшая нижняя граница B
и A
'[§5.1, Спецификация языка Scala]), но вы пытаетесь определить поле с тем же именем снова без явного переопределения.
Посмотрите на более простой пример:
trait A { val v = "a" }
trait B { this: A =>
var v = "b"
}
new A with B {} // does not compile
<console>:9: error: overriding value v in trait A$class of type java.lang.String;
variable v in trait B$class of type java.lang.String needs `override' modifier
new A with B {}
Итак, даже если вы не получили ошибку при определении B
, вы все равно просто не можете ее использовать.
Это сработает
trait A { val v = "a" }
trait B { this:A => override val v = "b" }
new A with B {}
Здесь вы явно переопределяете A
v
в B
.(Обратите внимание, что new B with A {}
потерпит неудачу, потому что B
должен стоять последним.) Кроме того, это должен быть val
, потому что в большинстве случаев вы не можете переопределить var
s, и вы не можете переопределить что-то еще, используя var
.
Как правило, в этих простых случаях вам не нужно беспокоиться о названии типа.Пока вы не создадите другую черту или класс внутри B
, и this
, и все, что вы бы назвали своей переменной собственного типа, будут указывать на одно и то же.Там не будет затенения.Если у вас есть новая черта внутри B
, и вам нужно сослаться на экземпляр B
внутри этой черты, вам потребуется другое имя для вашего собственного типа.
Учтите это
trait B { this =>
val v = "b"
trait C {
val v = "c"
println(this.v)
}
new C {}
}
new B {}
// prints c
против этого:
trait B { self =>
val v = "b"
trait C {
val v = "c"
println(this.v) // prints c
println(self.v) // prints b
}
new C {}
}
new B {}
(Без каких-либо дальнейших аннотаций типов вы можете опустить все this
в этом примере.)