要怎麼減少犯錯的機會呢?盡量減少fopen和fclose之間的距離,越近越好。最好是fopen完就呼叫fclose,這樣犯錯的可能性就降低很多了。
可是你fopen後馬上fclose,這樣好像也沒有意義。所以怎麼辦呢? go 語言引進了一個機制,類似物件的解構子,只是他是適用於 function。 當一個 function 的敘述是defer 開頭的,他不會立刻執行,他會等到函數結束時才會執行。
來看個簡單的例子。
package main
import "fmt"
func test(){
    fmt.Printf("test start\n")
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d\n", i)
    }
    fmt.Printf("test end\n")
}
func main(){
    test()
}
test start test end 4 3 2 1 0
你會發現,它是在印完 "test end" 後,才開始印數字。而導致這個結果都主因就是defer這個關鍵字。
defer 的作用是把後面接的指令 push 到 stack裡,等到 function執行完畢要返回到caller(在執行完return後)時,在從 stack 取出指令來執行。因為1是最先被push進去的,所以他最後被執行。
有了 defer 敘述,我們就可以這樣寫開檔指令
    f, err := os.Open("somefile", os.O_RDWR | os.O_CREATE, 0666)
    if err != nil {
        return
    }
    defer f.Close()
開檔案和關檔案的敘述靠的夠近,這樣就不怕忘記了!!當然,defer 在 go lang 裡另外一個作用就是和 panic 、 recover函數搭配,改天再寫這個。
這個 blog 也有介紹 defer 、panic、recover的用法
http://blog.golang.org/2010/08/defer-panic-and-recover.html
那個 blog 有個有趣的 defer 例子,程式碼如下。
func c() (i int) {
    defer func() { i++ }()
    return 1
}
上面那段程式碼 c 的回傳值將是2,這就是為什麼我之前強調執行 defer 敘述發上在 return 後。 至於他為什麼他會這樣設計,主要是為了panic、recover。當函數執行時發生panic時,可以在 defer 的 function 裡乎要recover,並在function修改回傳值。就像下面程式碼所示範的的,當程式有panic時,他會把 err_code 改成1。
package main
import "fmt"
func test(){
    fmt.Printf("test start\n")
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d\n", i)
    }
    fmt.Printf("test end\n")
}
func test1()(err_code int){
    defer func() {
        if r := recover(); r != nil{
            err_code = 1
        }
    }()
    panic("123")
    return 0
}
func main(){
    ret := test1()
    fmt.Printf("%d\n", ret)
}
沒有留言:
張貼留言