2017-09-06 55 views
2

我有一個簡單的語法初始化的對象爲空(由於圓形的依賴?)

Expr -> Byte | Sum Expr Expr 

和下面的代碼應該生成隨機樹爲它

object randomTree extends App { 
    // Expr -> Byte | Sum Expr Expr 
    def intRnd(len: Int, start: Int = 0): Int = (math.random * len toInt) + start 
    def byteRnd = intRnd(256, -128) 
    case class Value[A](value: A, parent: Type) extends Type { 
     def gen = this 
     override def toString = value + ":" + parent.getClass.getSimpleName 
    } 

    trait Type { 
     def gen: Type //def gen[A]: Value[A] 
     override def toString = getClass.getSimpleName 
    } 

    class OR/*Enum*/(alternatives: Type*) extends Type { 
     def gen = alternatives(intRnd(alternatives.length)).gen 
    } 

    class AND/*Sequence*/(alternatives: Type*) extends Type { 
     def gen = { 
      println("Sum " + alternatives)// prints: Sum WrappedArray(null, null) 
      Value(alternatives.map(_.gen), this) 
     } 
    } 

    object Expr extends OR(Sum, Byte) { 
     override def gen = Value(super.gen, this) 
    } 
    //object Sum extends Type { // everything is fine if this Sum is used 
     //def gen = Value(Expr.gen -> Expr.gen, this) } 
    println("Expr = " + Expr) // prints: Expr = Expr$ 
    object Sum extends AND(Expr, Expr) // this Sum causes NPE 
    object Byte extends Type { 
     def gen = Value(byteRnd, this) 
    } 
    (1 to 10) foreach { i=> println(Expr.gen) } 

} 

我不知道爲什麼object Sum extends AND(Expr, Expr)由於Expr是一個非空對象,因此擴展爲AND(WrappedArray(null, null)),我如何初始化Expr使得Sum出來正確?

回答

1

由於存在ExprSum之間的循環引用該真實引起空值By Name Parameter可以用來解決這一循環引用問題推遲對象的初始化。像:

... 
class OR /*Enum*/ (alternatives: => Array[Type]) extends Type { 
... 
class AND /*Sequence*/ (alternatives: => Array[Type]) extends Type { 
... 

在上面的代碼:alternatives: => Array[Type]作爲按名稱參數延遲圓形對象初始化時間,以避免空值。