モジュール 3 · レッスン 4 / 5コース内の 14/50~12 min
モジュールのレッスン (4/5)
値としてのクロージャと関数
Go では、関数は 第一級の値 です。関数は次の値に割り当てることができます。 変数を他の関数に渡して返します。 クロージャとは、 の変数を キャプチャする関数リテラル (匿名) それが定義される環境。
関数リテラル
インラインで記述された名前のない関数。すぐに電話をかけるか、 それを割り当てます:
Go
greet := func(name string) {
fmt.Println("ciao", name)
}
greet("Anna")
// invocata immediatamente:
func() { fmt.Println("subito") }()greet のタイプは func(string) です。
環境を捉える: クロージャ
関数リテラルは、以下に表示される変数を読み取り、変更できます。 外部関数が戻った後でも、その字句スコープは次のようになります。
Go
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c()) // 1 2 3n は、少なくとも 1 つのクロージャがそれを参照している限り「存続」します。それぞれの電話に
counter() は、新しい独立した n を作成します。
コールバックとしてのクロージャ
非常に一般的なパターン:
Go
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})クロージャは nums をキャプチャし、順序を定義します。
パラメータとしての関数
関数をパラメータとして受け入れるには、その型を書き出します。
Go
func apply(nums []int, f func(int) int) []int {
out := make([]int, len(nums))
for i, n := range nums {
out[i] = f(n)
}
return out
}
double := func(x int) int { return x * 2 }
apply([]int{1, 2, 3}, double) // [2 4 6]署名が読みにくくなった場合は、タイプ エイリアスを定義します。
Go
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }試してみてください
運動#go.m3.l4.e1
試行回数: 0読み込み中…
クロージャを返す counter() を定義します。クロージャを呼び出すたびにインクリメントされ、内部カウンタが返されます。
エディターを読み込み中…
ヒントを表示
`n` はリターンの前に宣言する必要があります。クロージャがそれをキャプチャします。
3 回の試行後に解決策が利用可能になります
運動#go.m3.l4.e2
試行回数: 0読み込み中…
「ciao」を出力する関数リテラルを f に代入し、それを呼び出します。
エディターを読み込み中…
ヒントを表示
構文: `f := func() { ... }`、次に `f()`。
3 回の試行後に解決策が利用可能になります
Quiz#go.m3.l4.e3
準備完了これは何を印刷しますか? (クロージャスコープに注意してください)
Go
mk := func() func() int {
x := 0
return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())要約
- 関数は最上級のものです: 割り当て可能、渡せる、返却可能。
- 関数リテラル:
func(params) ret { ... }、匿名。 - クロージャ: 字句スコープの変数をキャプチャし、それらを生きたままにします。
- パラメーターの明示的な関数タイプ:
func(int) int。 - Go 1.22 以降、すべての for 反復にはループ変数の独自のコピーがあります。