がばがばscala独学 - トレイト(3)


はじめに

下記のテキストを通して、基本的な書き方を学びつつ、個人的に気になったことを検証していくメモ代わりです。
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 を修正したほうがいい