16.2.2 实现 switch 函数
我们在上一节描述了 switch 函数的行为方式,其实现并不比直接把描述转换成代码更多,如清单 16.8 所示。关键点是,这个函数将返回一个行为,它使用存储在可变变量中的实际行为。每当发生事件时,我们会更新可变变量,所以,任何后续的对这个行为值的请求,都使用新的结果。注意,可变状态的这种使用方式,对用户是隐藏的,所以,最终用户代码可以是声明式的,无任何可见的副作用。
Listing 16.8 Implementing the switch function (F#)
let switch initialBehavior behaviorEvent =
let current = ref initialBehavior
behaviorEvent |> Observable.add (fun newBehavior –>
current := newBehavior)
sample(fun ctx –>
let (BehaviorFunc f) = !current
f(ctx))
清单 16.8 中的函数首先声明一个可变变量,使用了 F# 的引用单元(ref cell,我们在第 8 章讨论过)。引用单元格的初始值设置为初始的行为。接下来,为可以产生新的行为 的事件设置了处理程序,当事件发生时,引用单元格的值设置为从事件中获得的新的行为。在此示例中,我们不担心线程安全,因为当从 Windows 窗体中使用 switch 函数时,其状态只能从图形用户界面(单个)线程中访问 。从函数中返回的行为,是使用前一章的 sample 基元构造的。当 Lambda 函数被调用,以检索指定时间的行为值时,只是简单地取消对当前行为的引用,并使用它来处理请求。
如果事件的逻辑处理并不复杂,来自 Observable 模块的功能是很有用的。如果对一个事件的响应总是相同的,如果需要筛选事件,或者与其他事件组合,那么,声明式风格是很有用的。以声明方式描述更复杂逻辑的事件使用,并不简单。在下一节中,我们将讨论另一种技术,使用在第 13 章中看到的异步工作流,来处理图形用户界面的事件。