【実務向け】Go deferの使い方|実行タイミングと実装パターンを解説

Go言語を学び始めると必ず出てくるのが「defer」です。
一見シンプルですが、実行タイミングや挙動を理解していないとバグの原因になる重要機能でもあります。

本記事では、Goのdeferについて「使い方・タイミング・実務での活用方法」をわかりやすく解説します。


deferとは?

deferは、関数の終了時に実行される処理を予約するキーワードです。

defer fmt.Println("終了処理")

このコードは、その場では実行されず、関数が終わるタイミングで実行されます。


実行タイミング(ここ重要)

deferは以下のタイミングで実行されます👇

👉 関数のreturn直前

func main() {
defer fmt.Println("defer")

fmt.Println("start")
}

👉 出力

start
defer

つまり👇
「処理の最後に必ず実行される」


複数deferの挙動(LIFO)

deferは複数書くと、後から書いたものが先に実行されます。

defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")

👉 出力

3
2
1

👉 スタック構造(LIFO)です


実務での使い方①:ファイルクローズ

file, err := os.Open("test.txt")
if err != nil {
return err
}
defer file.Close()

👉 ポイント

  • 開いたらすぐdefer
  • 書き忘れ防止

実務での使い方②:DB接続のクローズ

db, err := sql.Open("mysql", dsn)
if err != nil {
return err
}
defer db.Close()

👉 接続リソースの解放は必須
👉 deferで安全に管理


実務での使い方③:ロック解除

mu.Lock()
defer mu.Unlock()

👉 エラーが起きても必ずUnlockされる
👉 並行処理では超重要


よくあるミス(重要)

❌ deferはすぐ評価される

defer fmt.Println(x)
x = 10

👉 出力は「元のx」

👉 理由

  • 引数はdefer時点で評価される

❌ ループ内deferの注意

for i := 0; i < 5; i++ {
defer fmt.Println(i)
}

👉 全部まとめて最後に実行される
👉 メモリ圧迫の原因になることも


実務でのベストプラクティス

✔ リソース開放は必ずdefer
✔ 関数の早い段階で書く
✔ ループ内で多用しない
✔ error処理と組み合わせる


エラーハンドリングとの組み合わせ

Goではdeferとerror処理を組み合わせるのが基本です。

func readFile() error {
file, err := os.Open("test.txt")
if err != nil {
return err
}
defer file.Close()

// 処理
return nil
}

👉
「エラー処理 × defer」=実務の基本パターン


まとめ

Goのdeferは、シンプルですが非常に強力な機能です。

ポイントは👇

  • 関数終了時に実行される
  • LIFOで処理される
  • リソース管理に必須
  • error処理と組み合わせる

💡 この記事の結論

👉
「リソースを開いたらすぐdeferで閉じる」

これを徹底するだけで、コード品質が一気に上がります。

コメント

タイトルとURLをコピーしました