見出し画像

Golang_関数とクロージャ #467

Golangの関数はクロージャをサポートしています。これにより、コードの再利用性と柔軟性を高めることが可能です。それぞれに関して整理していきたいと思います。

Golangの関数

Golangにクラスの概念はありませんが、他のプログラミング言語と同様に関数は存在しています。

基本的な関数

基本的な構文は以下の通りです。

func functionName(parameter1 type1, parameter2 type2) returnType {
    // 関数の処理
    return result
}

例として単純な関数を定義してみます。

package main

import (
	"fmt"
)

func add(a int, b int) int {
	return a + b
}

func main() {
	sum := add(3, 4)
	fmt.Println("Sum:", sum) // 出力: Sum: 7
}

関数リテラル (無名関数)

Golangでは関数リテラル(無名関数)もサポートしており、関数を変数に代入したり、他の関数に引数として渡したりできます。

上記のadd関数を関数リテラルにしてみます。

package main

import (
	"fmt"
)

func main() {
	// 無名関数を変数に代入
	add := func(a int, b int) int {
		return a + b
	}

	sum := add(5, 7)
	fmt.Println("Sum:", sum) // 出力: Sum: 12
}

Golangでは関数のこれらの機能を活かしてクロージャを実現します。

Golangのクロージャ

クロージャとは、関数とその関数が定義された環境(スコープ)を合わせたものです。

クロージャの基本

関数が定義された環境(スコープ)の変数を参照し、その変数の状態を保持します。これにより、関数が呼び出されるたびに、その外部変数にアクセスして変更を加えることができます。

クロージャは、それ自身の外部から変数を参照する関数値です。 この関数は、参照された変数へアクセスして変えることができ、その意味では、その関数は変数へ"バインド"( bind )されています。

A Tour of Go

実際のコードでクロージャの機能を見てみます。

package main

import "fmt"

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),   // 0から始まり、次々と値を加算していく
			neg(-2*i), // 0から始まり、次々と値を減算していく
		)
	}
}

adder()の冒頭でsumに0を代入していますが、posやnegにはreturn文の関数が入っている(そして外部変数にあたるsumにアクセスできる)ので、forでループしたとしてもsumが毎回0になってしまうわけではありません。

クロージャの使用場面

例えば以下のような場面で使用できます。

関数のカスタマイズ:
例)特定の設定を保持した関数を作成(以下は数字に常に特定の値を足す関数の例)

package main

import "fmt"

func makeAdder(x int) func(int) int {
	return func(y int) int {
		return x + y
	}
}

func main() {
	add5 := makeAdder(5)
	fmt.Println(add5(3)) // 出力: 8
	fmt.Println(add5(10)) // 出力: 15
}

関数の実行回数制限:
例)指定された回数だけ実行可能な関数

package main

import "fmt"

func makeLimitedFunc(limit int, fn func()) func() {
	count := 0
	return func() {
		if count < limit {
			count++
			fn()
		} else {
			fmt.Println("Function limit reached")
		}
	}
}

func main() {
	limitedFunc := makeLimitedFunc(3, func() {  // 3回をlimitに設定
		fmt.Println("Function called")
	})

	for i := 0; i < 5; i++ {
		limitedFunc()   // 4, 5回目はelseに入る
	}
}

データのカプセル化:
クロージャを使用してデータをカプセル化し、外部からの直接的なアクセスを防ぐことができます。これはプライベート変数を保持する方法として役立ちます。

package main

import "fmt"

func counter() func() int {
	count := 0
	return func() int {
		count++
		return count
	}
}

func main() {
	count := counter()
	fmt.Println(count()) // 出力: 1
	fmt.Println(count()) // 出力: 2
	fmt.Println(count()) // 出力: 3
}

上記では「count := 0」がカプセル化された箇所で、ここには外部から直接アクセスできず、クロージャを通じてのみ操作されます。


ここまでお読みいただきありがとうございました!!

参考


この記事が気に入ったらサポートをしてみませんか?