推迟执行代码

我们可以使用 unit 类型作为函数参数来定义我们之前不想执行的函数。这在异步后台任务中通常很有用,当主线程可能需要触发后台线程的某些预定义功能时,例如可能将其移动到新文件,或者如果不应立即运行 let-binding:

module Time =
    let now = System.DateTime.Now   // value is set and fixed for duration of program
    let now() = System.DateTime.Now // value is calculated when function is called (each time)

在下面的代码中,我们定义代码来启动一个 worker,它只是每 2 秒打印出它正在工作的值。然后,worker 返回两个可用于控制它的函数 - 一个将其移动到下一个值进行处理,另一个使其无法工作。这些必须是函数,因为我们不希望在我们选择之前执行它们的实体,否则工作者将立即移动到第二个值并在没有做任何事情的情况下关闭。

let startWorker value =
    let current = ref value
    let stop = ref false
    let nextValue () = current := !current + 1
    let stopOnNextTick () = stop := true
    let rec loop () = async {
        if !stop then
            printfn "Stopping work."
            return ()
        else
            printfn "Working on %d." !current
            do! Async.Sleep 2000
            return! loop () }
    Async.Start (loop ())
    nextValue, stopOnNextTick

然后,我们可以通过这样做来启动工人

let nextValue, stopOnNextTick = startWorker 12

工作将开始 - 如果我们在 F#交互式,我们将看到每两秒在控制台中打印出的消息。然后我们可以运行

nextValue ()

我们将看到表明正在处理的值已移至下一个值的消息。

什么时候结束工作,我们可以运行

stopOnNextTick ()

函数,将打印出结束消息,然后退出。

unit 类型在这里很重要,表示无输入 - 函数已经拥有了构建它们所需的所有信息,并且不允许调用者更改它。