2013-04-02 6 views
7

私が書く場合:サブタイプの形質の値をどのように初期化するか?

trait T { 
    val t = 3 
    val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

それはこのことを示しています。

私はそれが次のように表示させるために上記のコードを変更する必要がありますどのように
List(1, 0) 

List(1, 2) 

すなわちoverride val tトレイトTuためtの値を設定しますか?これを行うには

+1

あなたは 'lazy val'としてuを定義することができます –

答えて

12

一つの方法は、次のようにdefまたはlazy valを使用してuの評価を遅らせることである。

  • を:

    trait T { 
        def t = 3 
        def u = 1::t::Nil 
    } 
    
    class U extends T { 
        override def t = 2 
    } 
    
    (new U).u 
    

    または

    trait T { 
        val t = 3 
        lazy val u = 1::t::Nil 
    } 
    
    class U extends T { 
        override val t = 2 
    } 
    
    (new U).u 
    

    次のような違いがありますvalは、初期化中に式を評価します。

  • defは、式が毎回uを評価します
  • lazy valを使用した初期の初期化子を使用してみてください、それは
10

を最初u使用状況を評価し、その結果をキャッシュします:

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) 

は、例えば参照してください。早期初期化の詳細については、hereを参照してください。

+0

正しいが、読みやすさの理由から、私は遅延メソッドでキャッシュメソッドを使うことを好む。 クラスUにコードを追加する必要がある場合は、大括弧で入れることはできません。クラスUのように別のグループを作成する必要があります。{override val t = 2} T {... my code here ... } –

+0

このアプローチの問題点は、すべてのアクセスが同期して、 'lazy val'が実際に準備ができていることを確認することです。アプリケーションの速度が遅くなり、クリティカルパスでは盲目的に使用しないでください。 –

4

すべてのスカラ宣言スタイルは、ただの錯覚です。 Scalaはjvm上に構築され、javaのように動作します。

Evetythingはクラスであり、その使用法に依存しないようにする必要があります(JavaはC++ではなく、逐次的なビルドを賛否両論でサポートしています)。すべての形質はそれ自身の初期化コードを有し、多重形質クラスはそれぞれの初期化コードを1つずつ実行する。サブクラスで宣言されているAnyRefを使用すると、その値は初期化時にnullに設定されます。

すべてのvalはfinalまたはlazy(why using plain val in non-final classes)でなければなりません。だから私は初期化の順序を気にしないし、私が宣言的な言語を使っているというふりをするかもしれません。

また、私はオプション-Xcheckinitを使用しています:フィールドアクセサーにランタイムチェックを追加してください。

関連する問題