はじめに
下記のテキストを通して、基本的な書き方を学びつつ、個人的に気になったことを検証していくメモ代わりです。
https://dwango.github.io/scala_text/basic.html
本当にありがとう、dwango様・・・
トレイトの初期化順序
- ざっくりまとめ
- 初期化順序によっては、初期化されていない変数が出てくる
- 初期化できていない原因となるtraitを改善することが一番である
落とし穴
-
初期化順序によっては機能しない変数が出てくる
scala> :paste // Entering paste mode (ctrl-D to finish) trait A { val foo: String } trait B extends A { val bar = foo + "world" } class C extends B { val foo = "hello " def printBar(): Unit = println(bar) } (new C).printBar() // Exiting paste mode, now interpreting. nullworld defined trait A defined trait B defined class C
nullworld
となって、hello world
と期待した結果となっていない-
lazy
を使用して処理を遅延させるscala> :paste // Entering paste mode (ctrl-D to finish) trait A { val foo: String } trait B extends A { lazy val bar = foo + "world" } class C extends B { val foo = "hello " def printBar(): Unit = println(bar) } (new C).printBar // Exiting paste mode, now interpreting. hello world defined trait A defined trait B defined class C
初期化が実際に使われるまで遅延される
-
デメリット
- 通常の変数定義より若干処理が重い
- 複雑な呼び出しでデッドロックが発生
-
defによる定義
scala> :paste // Entering paste mode (ctrl-D to finish) trait A { val foo: String } trait B extends A { val bar = foo + "world" } class C(val foo:String) extends B { def printBar(): Unit = println(bar) } (new C("hello ")).printBar() // Exiting paste mode, now interpreting. hello world defined trait A defined trait B defined class C
- デメリット
- 毎回定義しなければならない点
- デメリット
-
事前定義(Early Definitions)を使う
scala> :paste // Entering paste mode (ctrl-D to finish) trait A { val foo: String } trait B extends A{ val bar = foo + "world" } class C extends { val foo = "hello" } with B { def printBar(): Unit = println(bar) } (new C).printBar() // Exiting paste mode, now interpreting. helloworld defined trait A defined trait B defined class C
根本的には
trait B
に問題があるため、trait B
を修正したほうがいい