《Effective Go》--defer

衣舞晨風發表於2017-11-11

    Go的defer語句用來排程一個函式呼叫(被延期的函式),使其在執行defer的函式即將返回之前才被執行。這是一種不尋常但又很有效的方法,用於處理類似於不管函式通過哪個執行路徑返回,資源都必須要被釋放的情況。典型的例子是對一個互斥解鎖,或者關閉一個檔案。

// Contents returns the file's contents as a string.
func Contents(filename string) (string, error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer f.Close()  // f.Close will run when we're finished.

    var result []byte
    buf := make([]byte, 100)
    for {
        n, err := f.Read(buf[0:])
        result = append(result, buf[0:n]...) // append is discussed later.
        if err != nil {
            if err == io.EOF {
                break
            }
            return "", err  // f will be closed if we return here.
        }
    }
    return string(result), nil // f will be closed if we return here.
} 

    對像Close這樣的函式呼叫進行延期,有兩個好處。首先,其確保了你不會忘記關閉檔案,如果你之後修改了函式增加一個新的返回路徑,會很容易犯這樣的錯。其次,這意味著關閉操作緊挨著開啟操作,這比將其放在函式結尾更加清晰。

    被延期執行的函式,它的引數(包括接收者,如果函式是一個方法)是在defer執行的時候被求值的,而不是在呼叫執行的時候。這樣除了不用擔心變數隨著函式的執行值會改變,這還意味著單個被延期執行的呼叫點可以延期多個函式執行。這裡有一個簡單的例子。

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

會列印出:

entering: b
in b
entering: a
in a
leaving: a
leaving: b

本文整理自:https://www.kancloud.cn/kancloud/effective/72206

個人微信公眾號:
這裡寫圖片描述

作者:jiankunking 出處:http://blog.csdn.net/jiankunking

相關文章