推遲執行程式碼

我們可以使用 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 型別在這裡很重要,表示無輸入 - 函式已經擁有了構建它們所需的所有資訊,並且不允許呼叫者更改它。