编译器抱怨延迟DelayedInit的类没有定义delayedInit方法

Rus*_*ell 2 scala

我有一个课程,我正在努力扩展DelayedInit:

class Foo extends DelayedInit {
  // expensive initialisation code
}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试运行时,sbt compile我收到错误:

Foo needs to be abstract, since method delayedInit in trait DelayedInit of type (x: => Unit)Unit is not defined
Run Code Online (Sandbox Code Playgroud)

我的理解是,通过扩展DelayedInit特征,任何初始化代码都应自动包装在一个闭包中,并delayedInit在初始化完成后在方法中运行.但是我用谷歌搜索了,似乎无法找到一个使用示例.我错过了什么?

Vla*_*dim 6

如何DelayedInit工作和它的用法示例

DelayedInit trait提供了控制在类或对象(但不是特征)中运行初始化代码的能力.

在继承自的类或对象(但不是特征)中的任何初始化代码在初始化DelayedInit期间由编译器传递给delayedInit方法,然后在您想要运行它时由您决定.

delayedInit 方法作为初始化的一部分自动调用,并且在该方法中直接作为参数传递的代码仍然在初始化期间运行代码.

让我们从一个基本场景开始:

object Main extends DelayedInit  {

   println ("  initialisation of Main object")
   override def delayedInit (body: => Unit) {
     println("delayedInit")
     body
   }

   def main (args: Array[String]) {
     println("main method") 
   }
}
Run Code Online (Sandbox Code Playgroud)

将打印:

delayedInit
  initialisation of Main object
main method
Run Code Online (Sandbox Code Playgroud)

实际上,delayedInit对于在类层次结构中继承特征的每个类,都会调用一次方法.一个稍微复杂的场景:

abstract class MyApplication extends DelayedInit {
   println ("  initialisation of MyApplication class")
}

object Main extends MyApplication  {

   println ("  initialisation of Main object")
   override def delayedInit (body: => Unit) {
     println("delayedInit")
     body
   }

   def main (args: Array[String]) {
     println("main method") 
   }
}
Run Code Online (Sandbox Code Playgroud)

将打印:

delayedInit
  initialisation of MyApplication class
delayedInit
  initialisation of Main object
main method
Run Code Online (Sandbox Code Playgroud)

由于main方法是初始化结束后第一个运行的方法,我们真正想做的是保存所有传递给delayedInit它的初始化代码并在以后运行它,可能是从内部运行main,因为我们可能有多个代码可以运行方便地将其存储在一个ListBuffer(我们需要继续保留自然执行顺序).'Main`对象中的代码可能如下所示:

private val init = new scala.collection.mutable.ListBuffer[()=>Unit]
override def delayedInit (body: => Unit) {
  println("delayedInit")
  init += (()=>body) // will result in NullPointerException
}


def main (args: Array[String]) {
  println("main method") 
  for (code <- init) code ()
}
Run Code Online (Sandbox Code Playgroud)

然而,有一个问题22:因为init字段的初始化与所有其他初始化语句一起被延迟,所以没有任何ListBuffer[()=>Unit]对象可以保留初始化代码供以后使用!

但要记住?

继承自的类或对象(但不是特征)中的任何初始化代码在初始化DelayedInit期间由编译器传递给delayedInit方法...

让我们重新洗牌一下,将记忆代码的功能移到以后StoredInit直接继承的特征中DelayedInit:

trait StoredInit extends DelayedInit {
   println ("initialisation of StoredInit trait")
   private val init = new scala.collection.mutable.ListBuffer[()=>Unit]
   override def delayedInit (body: => Unit) {
     println("delayedInit")
     init += (()=>body)
   }   
   def initialise () {
     for (code <- init) code ()     
   }
}

// extend StoredInit instead of DelayedInit
abstract class MyApplication extends StoredInit {
   println ("  initialisation of MyApplication class")
}

object Main extends MyApplication  {

   println ("  initialisation of Main object")

   def main (args: Array[String]) {
     println("main method") 
     initialise() // finally perform the delayed initialisation
   }
}
Run Code Online (Sandbox Code Playgroud)

将打印:

initialisation of StoredInit trait
delayedInit
delayedInit
main method
  initialisation of MyApplication class
  initialisation of Main object
Run Code Online (Sandbox Code Playgroud)

最后,为什么DelayedInittrait 不包含默认的delayedInit方法实现?

保持编译器钩子与延迟初始化行为的实际实现脱钩.对于必须在特定容器中工作的控制台应用程序和服务器端组件,所需的行为将有所不同.

trait App但是,它继承自DelayedInitScala应用程序并为其提供默认实现.