假設我有如下寫一些GUI代碼:使用Scala事件偵聽器延長部
widget1.addListener(event1 =>
handle1(event1)
widget2.addListener(event2 =>
handle2(event2)
widget3.addListener(event3 => handle3(event3))
)
)
你怎麼會寫它使用Scala的延續CPS風格?
假設我有如下寫一些GUI代碼:使用Scala事件偵聽器延長部
widget1.addListener(event1 =>
handle1(event1)
widget2.addListener(event2 =>
handle2(event2)
widget3.addListener(event3 => handle3(event3))
)
)
你怎麼會寫它使用Scala的延續CPS風格?
只是想提供工作的例子,除了其他答案。隨着斯卡拉延續它可以看起來像這樣:
import scala.util.continuations._
object ContinuationsExample extends App {
val widget1 = Widget()
val widget2 = Widget()
reset {
val event1 = widget1.getEvent
println("Handling first event: " + event1)
val event2 = widget2.getEvent
println("Handling second event: " + event2)
}
widget2 fireEvent Event("should not be handled")
widget1 fireEvent Event("event for first widget")
widget2 fireEvent Event("event for second widget")
widget1 fireEvent Event("one more event")
}
case class Event(text: String)
case class Widget() {
type Listener = Event => Unit
var listeners : List[Listener] = Nil
def getEvent = shift { (l: Listener) =>
listeners = l +: listeners
}
def fireEvent(event: Event) = listeners.foreach(_(event))
}
此代碼實際編譯和運行,所以你可以自己嘗試。您會收到以下輸出:
Handling first event: Event(event for first widget)
Handling second event: Event(event for second widget)
Handling first event: Event(one more event)
如果你編譯這個例子,那麼不要忘記對Scala編譯器提供-P:continuations:enable
參數,允許延續。
這裏有一個簡單的工作示例:
reset{
shift { (k: Unit => Unit) => widget1 addListener(handle1 _ andThen k)}
shift { (k: Unit => Unit) => widget2 addListener(handle2 _ andThen k)}
widget3 addListener(handle3 _)
}
你不需要'shift {k => handle1(event1); k}'? – 2011-05-19 20:42:44
另外請注意,這裏的重置實際上是多餘的,因爲換檔並不是真的從內部調用,儘管它起初可能會出現。在這個例子中,換班真的被任何想要運行事件處理功能的人所調用,並且沒有任何行會這樣做。 – 2011-05-19 20:58:43
感謝您的建議,我修改了代碼段 – 2011-05-19 22:31:43
有延續的關鍵是使用編碼的直接風格的能力,即使平時我將被迫代碼更難使用的方式(例如以事件驅動的風格)。
所以客戶端代碼我希望能寫會是這樣的:
reset {
val event1 = widget1.waitForEvent()
handle1(event1)
val event2 = widget2.waitForEvent()
handle2(event2)
val event3 = widget3.waitForEvent()
handle3(event3)
}
所以聽衆的東西就從我被隱藏。但是,當然,聽衆仍然需要在下面的某個地方。我會將它們隱藏在小部件的waitForEvent()方法中(可以添加到Widget類中,也可以通過隱式轉換獲得)。該方法看起來像:
def waitForEvent() = shift { k =>
this.addListener(event => k(event))
k
}
這至少在概念層面。爲了實現這個功能,你需要添加一些類型和/或@cps註釋。
實際上,這是編譯器插件,它將您的代碼轉換爲CPS格式。你的代碼應該是直接編寫的 - 這就是Scala延續支持的用途。我想這就是你的想法? – 2011-05-19 20:54:47
每次發生event1時,該代碼都會向widget2添加新的偵聽器。因此,第四次,widget2將向widget3添加三個監聽器! – nafg 2012-01-06 09:40:22