2017-09-06 7 views
2

J'ai une grammaire simpleobjet Initialisé est nulle (en raison de la dépendance circulaire?)

Expr -> Byte | Sum Expr Expr 

et le code ci-dessous est censé générer les arbres au hasard pour elle

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) } 

} 

Je me demande pourquoi object Sum extends AND(Expr, Expr) se développe en AND(WrappedArray(null, null)) puisque Expr est un objet non-nul et comment puis-je initialiser l'Expr de telle sorte que Somme vient à droite?

Répondre

1

Comme il y a une référence circulaire entre Expr et Sum qui a causé valeurs nulles, By Name Parameter peut être utilisé pour résoudre ce référence circulaire question de retarder l'initialisation de l'objet. comme:

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

Dans le code ci-dessus: alternatives: => Array[Type] comme Par paramètre Name pour retarder le pour éviter les valeurs nulles moment de l'initialisation de l'objet circulaire .