defer

defer 文は、関数を抜けるときに実行する処理を登録する。defer 文で登録する処理は関数またはメソッド呼び出しでなければならない。
例を示そう。

package main

import "fmt"

func bar() {
    defer fmt.Println("bar end")
    fmt.Println("bar start")
}

func foo() {
    defer fmt.Println("foo end")
    fmt.Println("foo start")
    bar()
}

func main() {
    foo()
}

関数 foobar でそれぞれ defer 文で処理を登録している。これを実行するとこうなる。

^o^ > go run defer.go
foo start
bar start
bar end
foo end

関数を抜けるときに処理が実行されているのがわかる。

defer 文で登録した処理は、ランタイムエラーが起こっても有効だ。次の例では一番深い関数呼び出し(baz)で panic を起こしている。この例でも defer 文で登録された処理は実行され、その後、エラーメッセージを表示する。

package main

import "fmt"

func baz() {
    panic("oops!")
}

func bar() {
    defer fmt.Println("bar end")
    fmt.Println("bar start")
    baz()
}

func foo() {
    defer fmt.Println("foo end")
    fmt.Println("foo start")
    bar()
}

func main() {
    foo()
}
^o^ > go run defer2.go
foo start
bar start
bar end
foo end
panic: oops!

goroutine 1 [running]:
main.baz()
        C:/Users/takatoh/Documents/w/learning-go/defer2.go:6 +0x6b
main.bar()
        C:/Users/takatoh/Documents/w/learning-go/defer2.go:12 +0x141
main.foo()
        C:/Users/takatoh/Documents/w/learning-go/defer2.go:18 +0x141
main.main()
        C:/Users/takatoh/Documents/w/learning-go/defer2.go:22 +0x27
exit status 2