2017-01-04 5 views
4

TestTrait1とTestTraitの2つの特性を考慮し、NewObjectが両方を拡張すると仮定します。 TestTraitのTestTrait1で変数を使用することです。以下のコードは完璧に動作します。Scala - App traitを使用した複数の継承

scala> trait TestTrait1 { 
| val arguments1: Array[String] = Array("1","2") 
| } 

defined trait TestTrait1 

scala> trait TestTrait { 
| val arguments: Array[String] 
| val len = arguments.length 
| } 

defined trait TestTrait 

scala> object NewObject extends TestTrait1 with TestTrait { 
| lazy val arguments = arguments1 
| } 

defined object NewObject 

scala> NewObject 
res30: NewObject.type = [email protected] 

今すぐTestTrait1をAppに置き換えてください。引数は遅延評価のために設定されているので、私はDelayedInitの場合でも以下のコードが動作すると仮定します。

scala> object NewObject extends App with TestTrait { 
| lazy val arguments = args 
| } 

しかし、そうではありません。これの背後にある理由は何ですか?

scala> NewObject 
java.lang.NullPointerException 
at TestTrait$class.$init$(<console>:12) 
... 35 elided 

この場合、TestTraitと同様の別の特性でargsを使用するソリューションは何ですか?

答えて

2
trait TestTrait1 { 
    val arguments1: Array[String] = Array("1","2") 
} 

trait TestTrait { 
    val arguments: Array[String] 
    val len = arguments.length 
} 

あなたは違いが表示された場合、TestTraitは熱心に初期化になるだろうメンバーlenを持っています。しかし、argsdef内にあり、デフォルト値はnullになります。Applenlazy valまたはdefに変更すると、NPEで爆発することはありません。

のクイックREPLセッションでこれを試してみましょう:

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait TestTrait { 
    def arguments: Array[String] 
    lazy val len = arguments.length 
} 

object NewObject extends App with TestTrait { 
    override lazy val arguments = super.args // Added `override` and `super` just for clarity. 
} 

// Exiting paste mode, now interpreting. 

defined trait TestTrait 
defined object NewObject 

scala> NewObject 
res0: NewObject.type = [email protected] 

scala> NewObject.arguments 
res1: Array[String] = null 

あなたが問題を再現したい場合は、以下のようにlenを呼び出すことができます。

scala> NewObject.len 
java.lang.NullPointerException 
    at TestTrait$class.len(<console>:12) 
    at NewObject$.len$lzycompute(<console>:15) 
    at NewObject$.len(<console>:15) 
    ... 33 elided 

をので、あなたの質問への答えはあなたですNewObjectのインスタンスを呼び出す場合は、lenlazy valまたはdefにする必要があります。 NewObjectをclassまたはtraitにすることをお勧めします。これは、安全でない/熱心に初期化されたlenメンバーがNPEで爆発することを望まないからです。

+1

これを同じ例で説明していただきありがとうございます。説明は理にかなっています。 – rashmina

関連する問題