yanom blog

様々な技術について書きます

知っているようで知らなかったGo言語のdefer

tl;dr

これどういう動作になるか分かりますか?

package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering: ", s)
    return s
}

func un(s string) {
    fmt.Println("leaving: ", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

分かりました?(私は間違えました...)
では、答えです。

C:\Windows\system32\cmd.exe /c ( go run main.go)
entering:  b
in b
entering:  a
in a
leaving:  a
leaving:  b

パッと見b()のprint文が最初に出力されそうですけど、そうではないんですね。
deferで指定されていても、内側のtrace("b")は実行されます。
ただし、un()はdefer指定されているので一番最後に実行されます。
ちなみに、deferの順番はLIFOです。(a -> bの順番)

まとめ

  • deferの指定の仕方を間違えると思わぬバグとなりそうです。
  • deferはLIFOです。
  • 2年くらいGo言語使ってますけど、新しい発見があって楽しい。