我有一个匿名类需要在它混入的特性之前进行初始化。早期初始化不起作用,因为它们不允许使用'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仍然首先初始化)?
答案 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)
简短回答:当然不是。
我们必须明白,有正当理由弯曲初始秩序的规律。思考那些尊重法律但仍然受其影响的灵魂。
有人谈论弃用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
,就不需要乱用初始化顺序。