Ответ 1
Под этим подразумевается следующая странность:
trait A {
val i: String
def j: String
}
class C extends A {
println ("val i = " + i)
println ("def j = " + j)
val i = "i"
def j = "j"
}
val c = new C
// prints
// val i = null
// def j = j
Итак, как вы видите, i
инициализируется значением по умолчанию (null
для AnyRef
), прежде чем он будет переопределен конструктором в C
. (def
объявления немедленно перенаправляются.)
Чтобы избежать этого, нужно было бы поместить инициализацию val
в начало конструктора, если это возможно.
Дополнительная странность (и как ее решить) в следующем случае
Рассмотрим
trait A {
val i: String
def j: String
}
abstract class D extends A {
println ("val i = " + i)
println ("def j = " + j)
}
class C extends D {
val i = "i"
def j = "j"
}
val c = new C
// prints
// val i = null
// def j = null
Теперь нам не повезло; похоже, что у нас нет возможности инициализировать val i
и def j
, прежде чем наш суперкласс D
попытается напечатать их.
Чтобы решить эту проблему, мы должны использовать ранние определения (§5.1.6 Scala ссылка):
class C extends {
val i = "i"
def j = "j"
} with D
val c = new C
// prints
// val i = i
// def j = j
И он работает!