2012-05-08 65 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