If I write :
trait T {
val t = 3
val u = 1::t::Nil
}
class U extends T {
override val t = 2
}
(new U).u
it shows this.
List(1, 0)
How should I change the above code to make it display the following:
List(1, 2)
ie override val t
sets the value of t
for u
in the trait T
?
One way to do this is to delay evaluation of u
by using def
or lazy val
as follows:
trait T {
def t = 3
def u = 1::t::Nil
}
class U extends T {
override def t = 2
}
(new U).u
or
trait T {
val t = 3
lazy val u = 1::t::Nil
}
class U extends T {
override val t = 2
}
(new U).u
The differences are as follows:
val
makes an expression evaluate during initialization def
makes an expression evaluate each time u
is used lazy val
makes it evaluated on first u
usage and caches the result Try using an early initializer:
scala> trait T {
| val t = 3
| val u = 1::t::Nil
| }
defined trait T
scala> class U extends {
| override val t = 2;
| } with T
defined class U
scala> (new U).u
res1: List[Int] = List(1, 2)
See eg here for more information about early initialization.
All scala declarative style is just an illusion. Scala is build upon a jvm and works like java.
Evetything is a class and should be independent on its usage (java is not c++ and supports incremental build with its pros and cons). Every trait has its own initialization code and multi-trait class runs respective initialization code one by one. If you use some AnyRef that is declared only in a subclass than that its value will be set for null during initialization.
I guard myself with specifing convention rule: every val should be either final or lazy ( why using plain val in non-final classes ) . So I don't care about initialization order and may pretend further that I'm using declarative language.
Also I'm using option -Xcheckinit
: Add runtime check to field accessors.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.