我还没有理解以下代码片段为什么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()
}
}
答案 0 :(得分:3)
afterDelay(0) {
println(...)
}
等同于以下内容:
afterDelay(0)({
println(...)
})
调用函数afterDelay
,新的WorkItem
(item
)被添加到列表中,而不是函数本身。参数 block: => Unit
是“按名称参数”(参见Scala Language Specification部分4.6.1):用作参数的表达式被隐式转换为“无参数方法” “(不首先评估),只要访问方法中的变量(不需要()
),就会调用它。
在这种情况下,当() => block
产生的函数被调用时:它会在item.action()
处调用,它发生在之后的 之后新WorkItem
已添加到列表中(并afterDelay
返回)。
如果它被写成(接受函数参数,而不是名字/ 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
。这表示相应的参数在函数应用程序点处未评估,而是在函数中的每次使用时进行评估。也就是说,使用call-by-name评估参数。
答案 1 :(得分:1)
您将afterDelay定义为curried function。这意味着它有两个参数列表。在scala中,您可以使用(...)
替换参数列表{...}
周围的括号。在第二个参数列表中,您使用的是"call-by-name" parameter。每次在您的函数中使用它们时,将再次评估这些参数。一个很好的例子是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
。