3

我有一个匿名类,需要在它混合的特征之前进行初始化。早期初始化不起作用,因为它们不允许使用“this”引用。如果我将类声明为具有 self 类型的内部特征,我可以使它工作,但这似乎不必要地冗长,因为该类型仅在代码中的一个地方使用,并且作为匿名类内联是直观的。但是,我似乎找到了 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 仍然首先初始化)?

4

3 回答 3

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被延迟。

于 2012-11-26T08:25:15.523 回答
1

简短的回答:当然不是。

我们必须相信你的话,弯曲初始化顺序的规律是有正当理由的。想一想那些尊重法律但仍然在法律之下受苦的灵魂。

@xiefei 的回答并不笨拙;它的结构足以影响您寻求的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
      }
    }
  }
}
于 2012-11-27T17:32:08.020 回答
0

请让我知道这是否完全错误/不合适,但这样的事情不会起作用吗?

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

outer._cache据我在这里了解,只要在任何东西使用它之前进行初始化,您就不必乱搞初始化顺序。

于 2017-10-18T07:03:55.667 回答