kakts-log

programming について調べたことを整理していきます

Go deferについて

Goには、deferステートメントというものがあり、deferへ渡した関数実行を、その呼び出し元の関数の終了時(return)まで遅延させることができます。

package main

import "fmt"

func main() {
  // main関数の最後に実行される
  defer fmt.Println("world.")

  fmt.Println("hello.")
}

出力
hello. world

deferステートメントの特徴として、deferに関数を渡す際、引数の値は、deferに渡すタイミングで評価されます。
以下のようなコードを書いて実行してみると、その挙動がわかって面白いです

package main

import "fmt"

func main() {
  var i = 1

  // i = 1が fmt.Printlnに渡され、最後に実行される
  defer fmt.Println("world. %d", i)
  
  // i = 2
  i++
  //  i = 2が fmt.Printlnに渡され、最後に実行される
  defer fmt.Println("world2. %d", i)

  // i = 2が渡され、その場で実行される
  fmt.Println("hello %d", i)
}

出力
hello %d 2
world2. %d 2
world. %d 1

まとめると、deferに渡した関数は、引数はその場で評価され、実行は呼び出し元の関数の終了時に行われる。
ここの挙動について簡単ですが、しっかり理解していないと複雑なコードになったときにバグの元になるため注意が必要です。