Scala语法首先初始化匿名类型

时间:2012-11-25 22:50:26

标签: scala initialization anonymous-types traits

我有一个匿名类需要在它混入的特性之前进行初始化。早期初始化不起作用,因为它们不允许使用'this'引用。如果我将类声明为具有自我类型的内部特征,我可以使它工作,但这似乎不必要地冗长,因为该类型仅在代码中的一个位置使用并且直观地作为匿名类内联。但是,我似乎找到了scala将接受的语法并满足我的初始化顺序要求。这是一个没有无关细节的简化示例(假设我有这样做的原因)。

trait WaitCondition[+T] {
...
}

trait EventWaitCondition[+T] extends WaitCondition[T] {
...
}

trait Event { outer =>
    private[this] var _cachedWaitCondition : Option[WaitCondition[T]]

    def next() : WaitCondition[T] =
        //Is there a way to "inline" the defintion of NextWaitCondition
        //without screwing up the initialization order?
        _cachedWaitCondition.getOrElse{ new NextWaitCondition with EventWaitCondition[T] }

    private[this] trait NextWaitCondition { this : WaitCondition[T] =>
        outer._cache = Some(this)
        ....
    }
    ....
}

所以,基本上,我的问题是有没有办法将NextWaitCondition的定义内联为匿名类型而不改变NextWaitCondition和WaitCondition之间的初始化顺序(即,以便NextWaitCondition仍然首先初始化)?

3 个答案:

答案 0 :(得分:1)

不确定这是你想要的,但也许DelayedInit特性可以帮助你。

trait WaitCondition[+T]

trait EventWaitCondition[+T] extends WaitCondition[T] with DelayedInit{
  def delayedInit(body: => Unit) = {
    body
    println("Initializing EventWaitCondition...")
  }
}

trait Event[T] { outer =>
  var _cachedWaitCondition: Option[WaitCondition[T]] = None
  var _cache: Option[WaitCondition[T]] = None

  def next(): WaitCondition[T] = _cachedWaitCondition.getOrElse(new EventWaitCondition[T] {
        println("Initializing NextWaitCondition...")
        outer._cache = Some(this)
      })
}

new Event[Int]{} next                           

//> Initializing NextWaitCondition...
//| Initializing EventWaitCondition...

这种方法的缺点是body delayedInit之后的初始化代码总是被延迟。

答案 1 :(得分:1)

简短回答:当然不是。

我们必须明白,有正当理由弯曲初始秩序的规律。思考那些尊重法律但仍然受其影响的灵魂。

@ xiefei的答案不是kludgy;它的结构足以影响你所寻求的kludge。

有人谈论弃用DelayedInit以支持postConstructor钩子;但是你真的要求一个preConstructor钩子,那么为什么不用模板方法来形式化呢?

根据你的Foo和SubFoo之间的依赖关系,这可能是一个更喜欢组合继承的问题。然后没有初始订单的游戏。

在下文中,首先使用模板方法概括您的命名解决方案。它的优点是只有使用网站知道或关心它。

trait Second {
  println("I must happen after first.")
}
trait SecondDelayed extends DelayedInit {
  println("SecondDelayed neutral stuff")
  def delayedInit(body: =>Unit) {
    body // body first
    println("I must be delayed after first.")
  }
}
trait Firstly {
  def firstly
  firstly
}

object Test extends App {
  def trial(t: =>Unit) {
    println("----")
    t
  }
  // candidate for least obnoxious
  trial {
    new Firstly with Second {
      def firstly {
        println("Do this firstly.")
      }
      println("Don't care when this happens.")
    }
  }
  trial {
    // current solution
    new Something with Second
    trait Something { this: Second =>
      println("First code.")
    }
  }
  trial {
    // prefer anon
    new Second {
      println("Anon first?") // nope
    }
  }
  trial {
    // DelayedInit solution
    new SecondDelayed {
      println("Anon first, then other delayed.")
    }
  }
  trial {
    // the "delayed" code must be idempotent,
    // or find a useful way to trigger execution;
    // here, the delayed code happens twice.
    class Foo extends SecondDelayed {
      println("Foo wants init, too")
    }
    new Foo {
      println("Anon first, then other delayed.")
    }
  }
  /* early defs are only for defs, with no this
  new {
    println("Anon first.")
  } with Second
  */
  trial {
    // trait code doesn't participate
    new DelayedInit with Second {
      def delayedInit(body: =>Unit) {
        println("My crucial early init business")
        body
      }
    }
  }
}

答案 2 :(得分:0)

如果这完全错误/不合适,请告诉我,但不会有这样的工作吗?

def next() : WaitCondition[T] = _cachedWaitCondition.getOrElse{ 
    new {
      outer._cache = Some(this)
    } with NextWaitCondition with EventWaitCondition[T]
  }

据我所知,只要在使用它之前初始化outer._cache,就不需要乱用初始化顺序。