Go言語のdeferを関数で使うテクニックと応用例!初心者でも理解できる遅延実行の使い方
生徒
「Go言語を勉強してると『defer』っていうのが出てきました。これは何に使うんですか?」
先生
「いいところに気がついたね。deferは、ある関数の処理を“あとで実行する”ための仕組みなんだ。主に後片付けに使うよ。」
生徒
「“あとで実行”ってどういうことですか?順番通りに動かないんですか?」
先生
「そう、順番どおりには動かない。deferを使うと、関数の最後にまとめて実行されるんだ。じゃあ、実際の使い方を見てみようか。」
1. deferとは?Go言語における遅延実行の基本
Go言語のdefer(ディファー)は、「関数の最後に実行してほしい処理」を指定するためのキーワードです。たとえば、ファイルを開いたあとに閉じる処理、データベースの接続解除など、最後にやっておくべきことを記述するのに使われます。
deferを使うことで、コードの読みやすさや安全性が高まります。たとえば、ファイルをうっかり閉じ忘れるといったミスを減らすことができます。
2. 基本的なdeferの使い方を見てみよう
それでは、簡単な例でdeferの基本動作を見てみましょう。
package main
import "fmt"
func main() {
fmt.Println("処理を開始します")
defer fmt.Println("最後に実行されます")
fmt.Println("メインの処理中です")
}
このプログラムを実行すると、出力結果は次のようになります:
処理を開始します
メインの処理中です
最後に実行されます
deferで指定したfmt.Println("最後に実行されます")は、main関数の処理が終わる直前に実行されています。
3. deferが便利な場面:ファイルを開いて自動で閉じる
プログラムでファイルを扱うとき、開いたら必ず閉じる必要があります。しかし閉じ忘れはよくあるミスです。そんなときdeferが役立ちます。
次のコードでは、ファイルを開いてから、関数の最後で確実にファイルを閉じています。
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 file.Close()と書くことで、関数の最後に自動でファイルを閉じてくれるため、書き忘れを防げます。
4. deferの実行順に注意しよう
複数のdeferを使うと、「最後に書いたものが最初に実行」されます。つまり、後入れ先出し(LIFO)という順序になります。
package main
import "fmt"
func main() {
defer fmt.Println("1番最後")
defer fmt.Println("2番目")
defer fmt.Println("最初に実行される")
}
このコードの出力結果は次のとおりです:
最初に実行される
2番目
1番最後
deferは書いた順ではなく逆順に実行されることを覚えておきましょう。
5. 関数でdeferを活用するテクニック
関数内でdeferを使うことで、処理の片付けやログ出力などを効率よく行えます。次の例は、「処理の開始」と「処理の終了」をログとして出力するものです。
package main
import "fmt"
func main() {
process()
}
func process() {
fmt.Println("処理開始")
defer fmt.Println("処理終了")
fmt.Println("データを処理しています...")
}
このように、関数の入り口と出口に関係する処理を簡潔に書けるのが、deferの大きな利点です。
6. deferの注意点と使いすぎのデメリット
便利なdeferですが、注意点もあります。
- 性能に影響する:
deferは毎回スタックに積まれるため、頻繁に使うとわずかですが処理速度に影響があります。 - ループ内で多用しない:ループの中で毎回
deferすると、メモリ使用量が増えることがあります。
使いどころを考えて、主に「関数の最後に絶対に実行しておきたい処理」に使うのがベストです。