初始化对象为空(由于循环依赖?)

时间:2017-09-06 09:02:32

标签: scala nullpointerexception circular-reference

我有一个简单的语法

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)会扩展为AND(WrappedArray(null, null)),因为Expr是一个非空对象,我如何初始化Expr以使Sum出现正确?

1 个答案:

答案 0 :(得分:1)

由于ExprSum之间有循环引用导致空值By Name Parameter可以用于解决此循环引用问题以延迟对象的初始化。像:

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

在上面的代码中:alternatives: => Array[Type]作为按名称参数来延迟循环对象初始化时间以避免空值。