基本的な使用方法
deferキーワードは通常、リソースのオープン後に配置され、後でリソースを閉じることを忘れないようにします。
deferで宣言されたコードは、実際には関数が終了するまで実行されません。
func demo_defer_0() {
fileName := "./test.txt"
f, _ := os.OpenFile(fileName, os.O_RDONLY, 0)
defer f.Close()
contents, _ := ioutil.ReadAll(f)
fmt.Println(string(contents))
}
複数のdefer呼び出しの順序:先入れ後出し(FILO)
func demo_defer_1() {
for i := 0; i < 3; i++ {
defer fmt.Println("defer:", i)
}
}
// defer: 2
// defer: 1
// defer: 0
スコープは現在の関数に制限されます
`
異なる関数には異なる関数スタックがあります。
func demo_defer_2() {
func() {
defer fmt.Println(1)
defer fmt.Println(2)
}()
fmt.Println("defer action")
func() {
defer fmt.Println("a")
defer fmt.Println("b")
}()
}
// 2
// 1
// defer action
// b
// a
deferの後の関数パラメータは値渡しです
func demo_defer_3_1() {
num := 0
defer func(n int) {
fmt.Println("defer:", n)
}(num)
for i := 0; i < 10; i++ {
num++
}
fmt.Println(num)
}
// 10
// defer: 0
func demo_defer_3_2() {
num := 0
p := &num
defer func(p *int) {
fmt.Println("defer:", *p)
}(p)
for i := 0; i < 10; i++ {
num++
}
fmt.Println(*p)
}
// 10
// defer: 10
func demo_defer_3_3() {
num := 0
defer func() {
fmt.Println("defer:", num)
}()
for i := 0; i < 10; i++ {
num++
}
fmt.Println(num)
}
// 10
// defer: 10
returnはdeferより先に実行されます
func demo_defer_4_1() (int, error) {
defer fmt.Println("defer")
return fmt.Println("return")
}
// return
// defer
func demo_defer_4_2() (num int) {
num = 10
defer func() {
num += 5
}()
return 2
}
// 7
最初に(num int)で、numは初期値0です。
その後、num = 10として、値が10に設定されます。
次に、return 2で、numが2に設定されます。
最後に、deferの中でnumが計算され、結果は7です。
func demo_defer_4_3() int {
num := 10
defer func() {
num += 5
}()
return 2
}
// 2
ここでは、numとreturnの値は関連していません。
panicが発生した場合、既に宣言されたdeferはスタックから実行されます
func demo_defer_5_1() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
panic("panic call")
defer fmt.Println(4) // 実行されません
}
func demo_defer_5_2() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
panic("panic call")
}