2017-11-02 6 views
0

の延長を評価するとき、私はこのようになります特色があります。で、しかし予期しない動作密閉された形質

object MyObject { 
    sealed trait c extends MyTrait { 
    val myItem: String 
    val description: String = s"$myItem" 
    } 

    object c1 extends c { 
    val myItem: String = "One" 
    } 

    object c2 extends c { 
    val myItem: String = "Two" 
    } 
} 

:私はその形質を呼び出して、次のを持っている別のオブジェクトで

trait MyTrait { 
    val description: String 
} 

を実行時間、I c1.descriptionおよびc2.descriptionは両方ともヌルオブジェクトです。私がこのようなコードをリファクタリングすると、予期した結果が得られます。

object MyObject { 
    sealed trait c extends MyTrait { 
    val myItem: String  
    } 

    object c1 extends c { 
    val myItem: String = "One" 
    val description = s"$myItem" 
    } 

    object c2 extends c { 
    val myItem: String = "Two" 
    val description = s"$myItem" 
    } 
} 

誰でもこの動作を説明できますか?

答えて

1

すべてのvalは外観順に評価されますが、オーバーライドvalはコンパイラによって評価され、評価されたコンパイル済みコードでは非オーバーライドの "under"です。だから、

object MyObject { 
    sealed trait c extends MyTrait { 
    val myItem: String = "This will print this string" 
    val description: String = s"$myItem" 
    } 

    object c1 extends c { 
    } 

    object c2 extends c { 
    } 
} 

作品、

object MyObject { 
    sealed trait c extends MyTrait { 
    val description: String = s"$myItem" 
    val myItem: String = "This will not print this string" 
    } 

    object c1 extends c { 
    } 

    object c2 extends c { 
    } 
} 

はない、とあなたが気づいたように、あなたの方法は、どちらかありません。

最も簡単なことは、記述を怠惰なvalとして書くことです。

より一般的なルールとして、私は通常、最終的な値(オーバーライドを禁止する)またはdefのいずれかを特質的に参照して、あらゆる種類のオーバーライドを許可します。あなたの場合、多分説明は最終的な怠け者であり、myItem a defでなければならないでしょうか?

+0

'c#myItem'を' def'に変更しても何も変更されないことに注意してください。 'c1'と' c2'の実装を変更する必要があります。 –

+0

'lazy val'を使うと問題が解決しました。 – franklin

0
  1. valは、コンストラクタの一部として初期化されます。それ以前はフィールドは存在しますが、デフォルト値(タイプによってはnull/0/falseなど)があります。

  2. スーパーcのコンストラクタ

  3. は、天然サブタイプ( c1又は c2)のコンストラクタの前に実行されます。

関連する問題