Go言語のdefer文の基本!処理の後に必ず実行する仕組みとは
生徒
「Go言語を勉強していて、deferっていうのを見かけたんですけど、何に使うんですか?」
先生
「deferは、ある関数の処理が終わった後に実行したい処理を、あらかじめ予約しておくためのキーワードなんです。」
生徒
「後で実行って、どんなときに便利なんですか?」
先生
「たとえば、ファイルを開いて作業した後に必ず閉じたいときや、プログラムの後始末を忘れずに行いたいときなどに便利ですよ。では、詳しく説明していきましょう!」
1. defer文とは?Go言語の基本キーワード
Go言語のdefer文(デファー文)は、特定の処理を「関数の最後」に実行したいときに使うキーワードです。「あとで実行してね」と命令するイメージで、処理の予約のような役割を持っています。
たとえば、掃除のときに「最後に電気を消す」と決めておくようなものです。プログラムでも、必ず実行したい後片付けや終了処理を忘れずに済ませられるため、初心者でも安心して使える仕組みになっています。
package main
import "fmt"
func main() {
defer fmt.Println("これは一番最後に表示されます")
fmt.Println("まずはメインの処理を実行中")
}
このサンプルでは、先に「メインの処理を実行中」と表示され、その後にdeferで予約しておいたメッセージが出力されます。どんな状況でも関数の終わりで実行されるため、後片付けを確実に行いたい場面でとても便利です。
2. defer文の基本的な使い方を覚えよう
まずは、いちばん基本の形から確認しましょう。defer文は「この関数が終わるときに、これを実行してね」と予約する書き方です。Go言語の後始末・後処理を安全に書けるので、初心者でも安心して使えます。
package main
import "fmt"
func main() {
fmt.Println("処理を開始します")
defer fmt.Println("最後に実行される処理です")
fmt.Println("メインの処理を実行中")
}
実行順は「開始 → メイン → 予約した処理」です。つまり、deferで予約した行は、関数の終了直前に必ず走ります。ここで覚えておきたいポイントは二つです。
- 引数はその場で評価される:
deferに渡した値や文字列は、予約した瞬間に決まります。 - 早期リターンでも必ず実行:途中で
returnしても、関数を出る直前に実行されます。
package main
import "fmt"
func greet(name string) {
defer fmt.Println("終了:", name) // nameはここで評価される
if name == "" {
fmt.Println("名前が未設定のため中断")
return // ここで抜けてもdeferは実行される
}
fmt.Println("こんにちは,", name)
}
func main() {
greet("太郎")
greet("")
}
こんにちは, 太郎
終了: 太郎
名前が未設定のため中断
終了:
このように、Go言語のdefer文は「関数終了時に必ず実行」「引数は予約時に評価」という性質をもつため、後片付けやログ出力などの後処理をシンプルに、安全に記述できます。まずはこの基本挙動をしっかり体で覚えておきましょう。
3. ファイル操作や後始末で活躍するdefer文
deferは、プログラムの「片付け」や「後始末」を自動化するための強い味方です。特に、ファイル・ネットワーク・データベースのように「開く/使う/必ず閉じる」が必要な場面で本領発揮します。書いた場所は処理の流れの中でも読みやすく、関数の最後で必ず呼ばれるため、閉じ忘れの心配を減らせます。
まずはファイルを開いて、最後に確実に閉じる基本パターンです。ポイントは、エラー確認の直後にdeferを書くこと。これで早期returnがあっても閉じ処理が失われません。
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("sample.txt")
if err != nil {
fmt.Println("ファイルを開けませんでした:", err)
return
}
defer file.Close() // 開けた直後に必ず予約
fmt.Println("ファイルを開いて処理中…")
// ここで読み取りや加工などのメイン処理を行う
}
次は、途中で条件により関数を抜ける場合でも、deferが実行されることを体感できる小さな例です。確認用のメッセージを入れて動きをつかみましょう。
package main
import (
"fmt"
"os"
"strings"
)
func process(path string) {
f, err := os.Open(path)
if err != nil {
fmt.Println("開けないため中断:", err)
return
}
defer func() {
fmt.Println("後始末: ファイルを閉じます")
f.Close()
}()
if !strings.HasSuffix(path, ".txt") {
fmt.Println("対象外の拡張子のため早期終了")
return // ここで抜けても上のdeferが必ず動く
}
fmt.Println("テキストファイルを処理中…")
}
func main() {
process("data.csv")
}
対象外の拡張子のため早期終了
後始末: ファイルを閉じます
このように、deferは「いつ関数を抜けても最後に必ず実行される」保証を与えてくれます。ファイル以外でも、ネットワーク応答のクローズ、テンポラリファイルの削除、ログの締め処理などで同じ考え方をそのまま使えます。まずは「開いたらすぐdeferで閉じる」を自然な習慣にして、安全で読みやすいGo言語のリソース管理を身につけましょう。
4. 複数のdefer文はどうなる?実行順序もチェック
deferは複数回使うこともできます。ただし、実行される順番に特徴があり、「後に書いたdeferが先に実行される(LIFO)」というルールになっています。
次のコードを見てください。
package main
import "fmt"
func main() {
defer fmt.Println("1つ目のdefer")
defer fmt.Println("2つ目のdefer")
fmt.Println("処理中...")
}
実行結果はこのようになります。
処理中...
2つ目のdefer
1つ目のdefer
このように、後からdeferで指定したものが先に実行されるため、「積み重ねた順に逆から」実行されると覚えておくといいでしょう。
5. 関数の中でパニック(エラー)が起きてもdeferは実行される
deferの強力な特徴は、関数の途中でエラーが発生しても、必ず実行されることです。これによって、安心して後始末を任せることができます。
次の例では、意図的にパニックを起こしていますが、deferはちゃんと実行されています。
package main
import "fmt"
func main() {
defer fmt.Println("プログラム終了処理中…")
fmt.Println("処理開始")
panic("何か問題が発生しました!")
}
出力は次のようになります。
処理開始
プログラム終了処理中…
panic: 何か問題が発生しました!
このように、エラー(パニック)が起きてもdeferの処理はきちんと呼ばれます。
6. defer文の使い方に注意するポイント
便利なdeferですが、次のような注意点もあります。
- 使いすぎるとコードが読みにくくなる:必要以上に多用すると、実行されるタイミングがわかりにくくなります。
- 実行されるのは「関数の終了時」:ループの中で使っても、関数が終わるまで実行されません。
- 実行コストがある:毎回呼び出し情報を保存するため、軽い処理に使いすぎないようにしましょう。
これらを意識して、deferは「確実に実行したい後始末」に使うのがベストです。
まとめ
Go言語のdefer文は「関数が終わる直前に、必ず実行したい処理を予約しておく」という、とても実用的な仕組みでした。この記事全体で、基本的な使い方から、ファイルやネットワーク処理での活躍、複数のdeferを使った場合の実行順序、そしてパニック(重大なエラー)が起きても確実に動作するという大切な特徴まで確認してきました。「関数が終わるまで待つ」「後片付けを忘れない」「予期しないエラーでも安全」は、実際のプログラミングで必ず役に立つ考え方です。
特に初心者の場合は、処理が終わったら必ず呼ばなければいけない関数を見落としてしまうことがあります。ファイルを閉じ忘れたり、ネットワーク接続を解除し忘れてしまったりすると、予想しない動作やトラブルにつながります。そこでdeferを使えば、関数を抜ける直前にまとめて実行してくれるので、「閉じ忘れた」「消し忘れた」というミスが減り、安心してコードを書くことができます。
また、複数のdeferを重ねて登録した場合は「後から書いたものが先に実行される」という特徴がありました。これはスタックという仕組みによるもので、プログラムの世界ではよく使われる考え方です。複雑な処理をしているときにも、逆順で後始末したい場面で役に立ちます。たとえば、複数のファイルや複数の接続を開いた場合、最後に開いたものを最初に閉じる方が都合がよいケースがあります。
そしてもうひとつ重要だったのは「パニックが起きてもdeferは動く」という点です。エラーはいつでも発生する可能性があり、思っていない場所で突然止まってしまうこともあります。そんなときでも、最低限の後処理が保証されるのは大きな安心材料です。ログの記録、接続の終了、ファイルのクローズなど、大切な処理を確実に守ることができます。
さらに、便利な反面、注意点もありました。ループの中でたくさん使うと、処理のタイミングが後回しになるため思っている動作と違う結果になることがあります。また、deferを大量に書きすぎると、予約した後処理を管理するための負荷が増えてしまいます。とはいえ、必要なタイミングで正しく使えば、これほど安心な道具はありません。「最後にこれは必ず実行してほしい」と思う場面で活用すれば、Go言語らしいきれいで読みやすいコードを書けるようになります。
簡単なサンプルでおさらい
最後に、これまでのポイントをぎゅっとまとめたシンプルなサンプルコードを紹介します。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("処理開始")
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("ファイルが開けませんでした:", err)
return
}
defer func() {
fmt.Println("後処理: ファイルを閉じます")
file.Close()
}()
fmt.Println("ファイルを使った処理中…")
fmt.Println("処理完了")
}
この短いプログラムの中にも、Go言語らしい安全な書き方が詰まっています。ファイルを無事に開けたら、すぐにdeferで閉じる処理を予約しておきます。途中でエラーが起きたり、何らかの理由で関数を抜けることになっても、最後にきちんとfile.Close()が呼ばれ、安全に片付けることができます。
実際の開発では、ファイルだけでなく、データベースの接続、ネットワークの通信、ログの書き込みなど、いろいろな場面で後処理が必要になります。そうした場所にdeferを書いておくことで、関数の終わりに確実に呼ばれ、ミスの少ない安定したプログラムを作ることができます。
生徒
「deferって、ただ最後に実行されるだけだと思っていたんですが、パニックが起きても実行されるのは安心ですね。」
先生
「そうなんです。もしdeferが無かったら、予期しないエラーが起きたときにファイルが閉じられないまま放置されてしまうこともあります。だから、安全なプログラムを作るうえでとても大事なんですよ。」
生徒
「ループの中で使った場合の動きも面白かったです。すぐに実行されるわけじゃないんですね。」
先生
「そうですね。ループごとに後処理したいなら、deferではなく普通にその場で関数を呼んだ方が良い場合もあります。適材適所で使うのがポイントです。」
生徒
「ファイル操作やネットワーク処理のときは積極的に使う、という感じですね。」
先生
「その通りです。大切なのは『必ずやりたい後片付け』です。そこにdeferを置くだけで、ミスが減り、読みやすいコードになります。実際の開発でもよく使うので、自然に身につくはずですよ。」
この記事を読んだ人からの質問
プログラミング初心者からのよくある疑問/質問を解決します
Go言語のdefer文は何のために使う構文ですか?初心者でも分かるように教えてください。
Go言語のdefer文は、関数の処理がすべて終わった後に必ず実行してほしい処理を予約する仕組みです。たとえば、ファイルを開いたあとに必ず閉じたい、データベースを使ったあとに必ず後片付けが必要、といった場面で使われます。後始末を自動化できるので、初心者でもミスを防げる安全な方法として役立ちます。
Go言語のdefer文を使うと、実際にはいつ実行されるのですか?処理の順番が知りたいです。
defer文は「関数が終了するとき」に実行されます。メインの処理より後になり、必ず最後に呼ばれるため、出力やログ、終了処理が確実に実行されます。メインの処理が終わってから実行されるため、順序を理解しやすいのも特徴です。
【超入門】ゼロから始めるGo言語プログラミング:最速で「動くアプリ」を作るマンツーマン指導
「プログラミングの仕組み」が根本からわかる。Go言語でバックエンド開発の第一歩を。
本講座を受講することで、単なる文法の暗記ではなく、「プログラムがコンピュータの中でどう動いているか」という本質的な理解につながります。シンプルながら強力なGo言語(Golang)を通じて、現代のバックエンドエンジニアに求められる基礎体力を最短距離で身につけます。
具体的な開発内容と環境
【つくるもの】
ターミナル(黒い画面)上で動作する「対話型計算プログラム」や、データを整理して表示する「ミニ・ツール」をゼロから作成します。自分の書いたコードが形になる感動を体験してください。
【開発環境】
プロの現場でシェアNo.1のVisual Studio Code (VS Code)を使用します。インストールから日本語化、Go言語用の拡張機能設定まで、現場基準の環境を一緒に構築します。
この60分で得られる3つの理解
「なぜ動くのか」という設定の仕組みを理解し、今後の独学で詰まらない土台を作ります。
データの種類やメモリの概念など、他言語にも通じるプログラミングの本質を学びます。
ただ動くだけでなく、誰が見ても分かりやすい「綺麗なコード」を書くための考え方を伝授します。
※本講座は、将来的にバックエンドエンジニアやクラウドインフラに興味がある未経験者のためのエントリー講座です。マンツーマン形式により、あなたの理解度に合わせて進行します。
初めてのGo言語を一緒に学びましょう!