2012-05-08 61 views
2

我还没有理解下面的代码片断为什么afterDelay(0) {...},一个本地定义的函数可以存储到议程?有人能帮我理解run函数中的afterDelay(0) {...}吗?斯卡拉,将本地定义的函数传递给列表?

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() 
    } 
} 

回答

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

等同于以下内容:

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

功能afterDelay调用一个新的WorkItemitem)被添加到列表中,而不是函数本身。参数block: => Unit是一个“按名称参数”(请参阅Scala Language Specification第4.6.1节):用作参数的表达式被隐式转换为将被调用的“无参数方法”(,而不是)只要访问方法内部的变量(不需要())。

在这种情况下即当从() => block产生的功能是调用:它是在其item.action()WorkItem被添加到列表中(和afterDelay返回)之后出现在一些点调用。

如果它被写为(以在功能paramater,而不是通过名字/ 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。这表明相应的参数是而不是在功能应用程序点评估,而是在功能内的每次使用中评估。也就是说,参数是使用名称来评估的。

+0

“这就是当函数结果()=>块被调用时,这里发生在afterDelay函数返回后的某个点上(在item.action())上。” - 在item.action()中调用afterDelay后?我感觉println(“*** simulation started,time =”+ currentTime +“***”),即afterDelay的()=>单位参数在item.action() – chen

+0

否,'afterDelay'在被调用时被调用。它创建一个* new *函数对象(它成为'WorkItem.action'),它关闭'block'参数(将其绑定到闭包中)。然后它创建新的'WorkItem',并将其排队;当* new *函数被调用时(通过其他地方的'item.action()'),那么它会导致评估名称参数(这将调用'println')。请将它与传入'()=> Unit'进行比较。 – 2012-05-08 05:08:38

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