Go言語のdeferキーワードを初心者向けに解説!

JavaScriptを有効にしてください

まえがき

Go言語を学び始めると、よく目にするキーワードの一つに「defer」があります。初心者の方にとっては、最初は少しわかりにくいかもしれませんが、実はとても便利でシンプルな機能です。今回は、そんなdeferキーワードの基本的な使い方から実用的な使い方、利点や注意点までを初心者向けにわかりやすく解説していきます。

基本的な使い方

Go言語の「defer」は、関数内で指定した処理を、その関数が終了する直前に実行するように予約するためのキーワードです。簡単な例を見てみましょう。

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
    defer fmt.Println("最後に実行されます")
    fmt.Println("最初に実行されます")
}

このコードを実行すると、以下のような結果になります。

1
2
最初に実行されます
最後に実行されます

このように、deferを使うと、関数の終了時に必ず実行したい処理を簡単に指定できます。

実用的な使い方

リソースの解放処理で使う

deferは主にリソースの解放処理に使われます。例えば、ファイルを開いた後に必ず閉じる処理を行いたい場合に便利です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Create("example.txt")
	if err != nil {
		fmt.Println("ファイルを作成できませんでした:", err)
		return
	}
	defer func() {
		file.Close()
		fmt.Println("ファイルを閉じました")
	}()

	// ファイルを使った処理をここに書く
	fmt.Println("ファイルを作成しました")
}

実行結果は以下のようになります。

1
2
ファイルを作成しました
ファイルを閉じました

defer に無名関数を使う理由

上記のコードでは defer の後に無名関数 (func() { ... }) を使っています。最初の例の通り、defer file.Close() のように直接 Close を呼ぶこともできますが、無名関数を使うことで以下のメリットがあります。

  1. 複数の処理をまとめて実行できる

    • defer file.Close() だけではなく、fmt.Println("ファイルを閉じました") などの追加処理を一緒に記述できる。
  2. ローカル変数の値を正しく参照できる

    • defer は関数が終了する直前に実行されるため、その時点の変数の値を使うことができる。無名関数の中で処理を書くことで、defer の実行タイミングでの状態を確実に反映できる。

複数のdeferを使う

また、複数のdeferを使った場合は、後に書いたものから順番に実行されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
    defer fmt.Println("1番目のdefer")
    defer fmt.Println("2番目のdefer")
    defer fmt.Println("3番目のdefer")

    fmt.Println("関数の処理")
}

実行結果は以下のようになります。

1
2
3
4
関数の処理
3番目のdefer
2番目のdefer
1番目のdefer

利点

deferを使うことには以下のような利点があります。

  • リソースの解放処理を忘れずに行えるため、メモリリークやファイルの閉じ忘れを防げる
  • コードがシンプルで読みやすくなる
  • エラー処理やパニック時にも確実に実行されるため、安全性が向上する

特に、エラーが発生した場合やパニックが起きた場合でも、deferで指定した処理は必ず実行されるため、リソースの解放処理を確実に行うことができます。

注意点

便利なdeferですが、いくつか注意点もあります。

  • deferは関数単位で動作するため、ループ内で大量に使うとリソースが解放されるタイミングが遅くなり、予期しない挙動を引き起こす可能性があります。
  • deferで指定した関数の引数は、deferを呼び出した時点で評価されます。実行時ではないため、引数の値が後で変わっても反映されません。

例えば、以下のコードを見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import "fmt"

func main() {
    i := 0
    defer fmt.Println("deferでのiの値:", i)
    i = 10
    fmt.Println("関数内でのiの値:", i)
}

実行結果は以下のようになります。

1
2
関数内でのiの値: 10
deferでのiの値: 0

このように、deferの引数は呼び出し時点で評価されるため、後から変化した値は反映されないことに注意しましょう。

あとがき

今回はGo言語のdeferキーワードについて、初心者向けに基本的な使い方から実用例、利点や注意点までを解説しました。deferをうまく活用することで、コードの安全性や可読性を高めることができます。ぜひ、実際のプログラムで積極的に使ってみてください。


スポンサーリンク

共有

もふもふ

プロフィール

著者
もふもふ
プログラマ。汎用系→ゲームエンジニア→Webエンジニア→QAエンジニア