2012-09-14 53 views
1

在由Twitter公佈的文件「Effective Scala」,我看到的代碼示例:Twitter的「有效斯卡拉」經紀人例子和尾遞歸

class Pool(conns: Seq[Conn]) { 
    private[this] val waiters = new Broker[Conn] 
    private[this] val returnConn = new Broker[Conn] 

    val get: Offer[Conn] = waiters.recv 
    def put(c: Conn) { returnConn ! c } 

    private[this] def loop(connq: Queue[Conn]) { 
    Offer.choose(
     if (connq.isEmpty) Offer.never else { 
     val (head, rest) = connq.dequeue 
     waiters.send(head) { _ => loop(rest) } 
     }, 
     returnConn.recv { c => loop(connq enqueue c) } 
    ).sync() 
    } 

    loop(Queue.empty ++ conns) 
} 

代碼不會顯得尾遞歸,和ISN」 t註釋如此。由於這是一個可能會在程序生命週期中保持運行的連接池,因此會阻止這樣的池最終炸燬堆棧並生成StackOverflowException?

回答

6

代碼根本不是遞歸的! loop不會自行調用。它分別通過關閉{ _ => loop(rest) }{ c => loop(connq enqueue c) }waiters.sendreturnConn.recv,它們再次調用loop。沒有遞歸因此沒有堆棧溢出。

+1

'send'和'recv'本身不帶thunk,但是它們返回的'Offer'的apply方法確實需要變換器(在這種情況下爲'(Conn)=> Unit'),它們實際上是回調函數成功的事務('Tx.Commit [Conn]'),所以每個'loop'調用只保留前一個調用的connq。 –