January 21st, 2015
- 經常在處理檔案的開關必須要注意到file open就一定要有搭配的 file close.但是如果有很多的case,搭配著很多的return.那是不是就得在每個地方寫上fclose?
func FileProcess() error {
//開啟檔案
f, err := os.Create("/tmp/dat2")
check(err)
//在這裡呼叫 defer f.Close(),如果有參數會這時候讀入
defer f.Close()
if CASE1 {
Do something
//這時候會執行 f.Close()
return errors.New("Error Case2")
} else if CASE2 {
Do something
//這時候會執行 f.Close()
return errors.New("Error Case2")
}
// 就算之後要增加新的case,也不用擔心要補 f.Close()
//這時候會執行 f.Close()
return nil
}
- Golang裡面有個很方便的function 叫做defer,他執行的時間點會是在你離開目前的function.
- 不過這裡需要注意的是有兩個地方:
- 變數的傳遞,會在呼叫defer的時候傳入.所以他並不是很簡單的直接移到最後呼叫
- 根據GoDoc Defer: The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes.
- 呼叫與執行defer採取的是LIFO.
- 變數的傳遞,會在呼叫defer的時候傳入.所以他並不是很簡單的直接移到最後呼叫
- 參考這篇文章
- 結論:
- defer最好還是使用在fopen與fclose比較不會有問題.
- 如果有參數要帶,千萬要想清楚當時參數的順序與是否有其他問題會發生.
package main
import (
"errors"
"fmt"
)
func useAClosure() error {
var err error
defer func() {
fmt.Printf("useAClosure: err has value %v\n", err)
}()
err = errors.New("Error 1")
fmt.Println("Finish func useAClosure")
return err
}
func deferPrintf() error {
var err error
//呼叫的時候會把參數帶過去,所以err是nil
defer fmt.Printf("deferPrintf: err has value %v\n", err)
err = errors.New("Error 2")
//注意這裡是LIFO,所以呼叫會是43210
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
fmt.Println("Finish func deferPrintf")
return err
}
func main() {
useAClosure()
deferPrintf()
}
/* output
Finish func useAClosure
useAClosure: err has value Error 1
Finish func deferPrintf
4 3 2 1 0 deferPrintf: err has value
*/
</pre>