LoginSignup
1
0

More than 1 year has passed since last update.

deferの即時評価

Posted at

Go言語の勉強を始めたのですが、deferで引っかかってしまった部分があったのでまとめまてみました。

defer ステートメントは、 defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させるものです。

defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。

引用元:A Tour of Go

上記の通りdeferを使うことで、呼び出している関数がreturnするまで処理の実行を遅らせることができます。
例えばファイルを閉じたりチャネルをクローズするのに使われます。

サンプルコード
func main() {
    file, _ := os.Open("./example.txt")
    defer file.Close()
    data := make([]byte, 100)
    file.Read(data)
    fmt.Println(string(data))
}




そして引っかかってしまった部分は

func main() {
    var fruit string = "Orange"
    defer fmt.Println(fruit)
    fruit = "Apple"
}

結果:Orange

Appleが帰ってくると予想していたので、???となってしまいました。
実は引用文の2行目に非常に重要なことが書かれています。

defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。

つまりdeferへ渡した関数の引数は、deferが評価された時点で値が保持されてしまうということです。だからdeferの評価後に変数fruitの値を変更しても、deferでの実行には反映されていなかったのです。

他にもdeferを使ってpanicからrecoverするとき、

panic/recover
func main() {
    defer func() {
    s := recover()
    fmt.Println(s,"ok")
    }()
    panic("panic!!!")
}

これだとrecoverできてokが出力されますが、

panic/recover
func main() {
    panic("panic!!!")   
    defer func() {
    s := recover()
    fmt.Println(s,"ok")
    }()
}

このようにpanicをdeferより前に書いてしまうとそのままプログラムが終了してしまいます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0