Error Handling
defer: 引数は登録時に評価され、呼び出しはLIFOになる
deferは関数終了時に実行されますが、引数はdefer文を通過した時点で評価されます。
Sourcedefer.go
Go 1.22
package deferflow
func CapturedArgument() (events []string) {
events = []string{}
label := "before"
defer func(value string) {
events = append(events, value)
}(label)
label = "after"
return
}
func LIFO() (events []int) {
defer func() { events = append(events, 1) }()
defer func() { events = append(events, 2) }()
return events
}Testdefer_test.go
Go 1.22
package deferflow
import (
"reflect"
"testing"
)
func TestDeferの引数はdefer文を実行した時点で評価される(t *testing.T) {
if got, want := CapturedArgument(), []string{"before"}; !reflect.DeepEqual(got, want) {
t.Fatalf("CapturedArgument() = %v, want %v", got, want)
}
}
func TestDeferは後に登録した関数からLIFO順に実行される(t *testing.T) {
if got, want := LIFO(), []int{2, 1}; !reflect.DeepEqual(got, want) {
t.Fatalf("LIFO() = %v, want %v", got, want)
}
}01Assertion
このテストで確認できること
- labelをafterへ変更してもdefer引数はbeforeのままになる
- 複数のdeferは後に登録した処理から実行される
closeやrollbackの順序はdeferのLIFOで決まります。変更前の値をdeferへ渡すコードでは、引数評価が即時であることをテストで固定します。
OBSERVED RESULT
captured argument → before
LIFO order → [2 1]