2

我还没有理解下面的代码片段afterDelay(0) {...},为什么本地定义的函数可以存储到议程中?有人可以帮我理解函数afterDelay(0) {...}中的内容吗?run

abstract class Simulation {

  type Action = () => Unit

  case class WorkItem(time: Int, action: Action)

  private var curtime = 0
  def currentTime: Int = curtime

  private var agenda: List[WorkItem] = List()

  private def insert(ag: List[WorkItem], item: WorkItem): List[WorkItem] = {
    if (ag.isEmpty || item.time < ag.head.time) item :: ag
    else ag.head :: insert(ag.tail, item)
  }

  def afterDelay(delay: Int)(block: => Unit) {
    val item = WorkItem(currentTime + delay, () => block)
    agenda = insert(agenda, item)
  }

  private def next() {
    (agenda: @unchecked) match {
      case item :: rest => 
        agenda = rest 
        curtime = item.time
        item.action()
    }
  }

  def run() {
    afterDelay(0) {
      println("*** simulation started, time = "+
          currentTime +" ***")
    }
    while (!agenda.isEmpty) next()
  }
}
4

2 回答 2

3
afterDelay(0) {
    println(...)
}

等价于以下内容:

afterDelay(0)({
    println(...)
})

调用函数时afterDelay,会将新WorkItem( item) 添加到列表中,而不是函数本身。该参数block: => Unit是一个“按名称参数”(参见Scala 语言规范第 4.6.1 节):用作参数的表达式被隐式转换为“无参数方法”(无需先评估),每当变量访问方法内部(()不需要)。

() => block在这种情况下,就是调用生成的函数时:它被调用,在新添加到列表(并返回)之后item.action()的某个时间点发生。WorkItemafterDelay

如果它被写成(接受一个函数参数,而不是一个名字/thunk):

def afterDelay(delay: Int)(block: () => Unit) {   // take a function
  // new function will invoke function named by "block" when invoked ...
  val item = WorkItem(..., () => block())
  // or skip wrapping the function in a function ...
  // val item = WorkItem(..., block)
  ...
}

然后需要传入一个函数来调用它:

afterDelay(0)(() => { // need a function
    println(...)
})

或者,替代语法,仍然是 的函数() => Unit,但可以避免外括号:

afterDelay(0) { () => // need a function
    println(...)
} 

从 SLS 中提取,4.6.1 按名称参数:

值参数的类型可以以 为前缀=>,例如x: => T。这种参数的类型就是无参数方法类型=> T。这表明相应的参数不会在函数应用时进行评估,而是在函数内的每次使用时进行评估。也就是说,使用按名称调用来评估参数。

于 2012-05-08T04:33:08.470 回答
1

您将 afterDelay 定义为 curried函数。这意味着它有两个参数列表。在 scala 中,您可以将参数列表周围的括号替换(...){...}. 在第二个参数列表中,您使用的是“按名称调用”参数。每次您在函数中再次使用这些参数时,都会对这些参数进行评估。一个很好的例子是here
“按名称调用”参数通常用于定义您自己的控制结构。

def do(until: Int)(body: => Unit) {
  body
  if (until > 1) do(until - 1)(body)
}

do(0)(println("test"))
do(5)(println("test2"))

这是一个执行直到的示例。它将打印一次test和五次test2

于 2012-05-08T07:09:49.213 回答