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

panic

組み込み関数 panic は、エラーメッセージを表示して、プログラムを中断する。何か致命的なエラーが起こった場合に使用する。
簡単な例を示そう。関数 fact は 0 以上の整数に値を返し、それ以外の場合には panic を呼ぶ。

package main

import "fmt"

func fact(n int) (int, error) {
    if n < 0 { panic("fact : domain error") } a := 1 for ; n > 1; n-- {
        a *= n
    }
    return a, nil
}

func main() {
    for x := 10; x >= -1; x-- {
        v, err := fact(x)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Println(v)
        }
    }
}

実行例。

^o^ > go run panic.go
3628800
362880
40320
5040
720
120
24
6
2
1
1
panic: fact : domain error

goroutine 1 [running]:
main.fact(0xffffffffffffffff, 0x1, 0x1, 0x2)
        C:/Users/takatoh/Documents/w/learning-go/panic.go:7 +0xb8
main.main()
        C:/Users/takatoh/Documents/w/learning-go/panic.go:18 +0x43
exit status 2

for ループの最後で fact-1 を与えているので panic が呼ばれている。