Go言語のクロージャとは?関数内関数の活用例と仕組み
生徒
「Go言語っていうプログラミングで、クロージャって聞いたんですけど、何なんですか?」
先生
「いい質問ですね。クロージャとは、関数の中で作られた関数のことです。Go言語では関数を他の関数の中で定義して、記憶させることができるんですよ。」
生徒
「えっ?関数の中に関数があるんですか?それって何か便利なんですか?」
先生
「とっても便利ですよ!じゃあ、仕組みと使い方を具体的に見ていきましょう!」
1. クロージャとは?基本の考え方を理解しよう
Go言語(Golang)のクロージャとは、関数の中で定義された関数で、外側の関数の変数などを覚えて使うことができるものです。
たとえば、「台所の蛇口をひねると水が出る」というイメージで、蛇口(内側の関数)には、どの水道管(外側の関数の変数)につながっているかが記憶されている感じです。
2. クロージャを使った簡単な例
それでは、Go言語で実際にクロージャを使ってみましょう。
package main
import "fmt"
func main() {
adder := createAdder()
fmt.Println(adder(5)) // 出力: 5
fmt.Println(adder(3)) // 出力: 8
fmt.Println(adder(10)) // 出力: 18
}
func createAdder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
このコードでは、createAdderという関数が、別の関数(クロージャ)を返しています。そしてその関数はsumという変数を記憶して使い続けています。
3. 実行結果を確認してみよう
上のプログラムを実行すると、以下のような出力になります。
5
8
18
呼び出すたびに、足した結果が蓄積されているのがわかります。これは、sumの値をクロージャが覚えているからです。
4. なぜクロージャが便利なの?
クロージャを使うと、「ある状態を覚えておく関数」を作ることができます。普通の関数は毎回ゼロから計算をしますが、クロージャは前の計算結果を記憶して次に活かすことができます。
これにより、同じ処理を繰り返すような場面や、特定の条件に応じて振る舞いが変わる関数を作るのに非常に役立ちます。
5. 関数を変数のように扱えるGo言語の特性
Go言語では、関数も値として変数に代入することができます。これがクロージャを活用するうえでとても重要なポイントです。
関数を変数に入れて、その変数を使って関数を呼び出すことで、まるで特別な処理機能を持った変数のように扱うことができるのです。
6. 複数のクロージャを作るとどうなる?
では、createAdderをもう一度呼び出したらどうなるでしょうか?実験してみましょう。
package main
import "fmt"
func main() {
adder1 := createAdder()
adder2 := createAdder()
fmt.Println(adder1(1)) // 出力: 1
fmt.Println(adder1(2)) // 出力: 3
fmt.Println(adder2(10)) // 出力: 10
fmt.Println(adder2(20)) // 出力: 30
}
func createAdder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
結果は以下のようになります:
1
3
10
30
adder1とadder2は別々のsumを持っていて、お互いの影響を受けません。これが状態を持つ関数の力です。
7. クロージャが使われる場面とは?
クロージャは、次のような場面でよく使われます:
- 何かの処理を段階的に進めたいとき(状態を記憶)
- 条件に応じて関数の動きを変えたいとき
- 関数を引数として渡すときに、その関数に特定の値を記憶させておきたいとき
たとえばゲームで「スコアを足していく処理」や「買い物の合計金額を覚えていく処理」などにも使えます。
まとめ
この記事ではGo言語におけるクロージャについて、その仕組みと活用方法をやさしく解説しました。クロージャは、外側の関数の変数を覚えて利用できる関数内関数のことで、Go言語の大きな特徴の一つです。通常の関数は呼び出すたびに新しい処理を行いますが、クロージャは「状態を保持し続けること」ができます。そのため、累積計算、状態管理、イベント処理、カスタマイズされた処理の作成など、実践的なプログラミングで非常に役立ちます。
さらに、クロージャはGo言語の「関数も値として扱える」という特性と組み合わさることで、柔軟かつ強力なコード設計を可能にします。特にWeb開発やAPI設計、ゲーム開発など多様な場面で利用され、コードの再利用性や拡張性を高めます。たとえば「カウンター機能」や「リスナー関数」などは典型的なクロージャの活用例です。
以下に、もう一度整理したサンプルコードを載せておきます。クロージャが変数を記憶して、呼び出しのたびに異なる結果を返す様子を確認できます。
package main
import "fmt"
func main() {
counter := createCounter()
fmt.Println(counter()) // 出力: 1
fmt.Println(counter()) // 出力: 2
fmt.Println(counter()) // 出力: 3
}
func createCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
この例ではcreateCounterが新しい関数を返し、その関数はcountという外側の変数を覚えています。呼び出すたびにcountが増えていくのは、まさにクロージャの特徴です。このようにクロージャを活用することで、Go言語プログラミングでは状態を扱いやすく、シンプルで明快なコードを実現できます。
生徒
「先生、今日の記事でクロージャのことがよく分かりました!Go言語では関数の中に関数を作れて、その関数が変数を覚えてくれるんですよね?」
先生
「その通りです。外側の変数を覚える関数、それがクロージャです。例えばカウンターを作るときや、計算の途中経過を保持したいときにとても便利ですね。」
生徒
「なるほど!普通の関数は呼ぶたびにリセットされるけど、クロージャなら前の状態を持ったまま次に進めるんですね。これならスコア計算や買い物の合計金額を覚えておく処理にも使えそうです!」
先生
「そうですね。Go言語では関数を値として扱えるので、クロージャと組み合わせるとプログラミングの幅がぐっと広がります。Webアプリやゲーム開発、サーバーサイドのAPI処理でもよく使われていますよ。」
生徒
「わあ、すごい!実際にサンプルプログラムを動かしてみたら、呼び出すたびに数字が増えていくのが本当に面白かったです。Go言語のクロージャをもっと練習して、自分のプログラムにも使ってみたいです!」
先生
「素晴らしい意欲ですね。クロージャをしっかり理解すれば、より高度なGo言語プログラミングにも自信を持って取り組めるようになりますよ。」