LoginSignup
1
0

More than 3 years have passed since last update.

クロージャと変数

Last updated at Posted at 2020-04-23

当記事の目的

最近Goの勉強を始めて、いまいち掴めないクロージャについて、
備忘録もかねて自分なりに整理した考えを記載しておこうと思います。

クロージャとは

Go 言語 公式の「A Tour of Go」には以下の説明があります。

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

Goでは、関数は第一級オブジェクトとして捉えています。
そのため、数値や文字列のように 関数そのものを変数に束縛や代入することも、引数または戻り値とすることができたりします。
クロージャとは、この関数を戻り値とするもしくは引数とする際に、これらの関数を参照する値、情報を指している。
(以下でいうと、adder()の返す値がクロージャにあたる)

Function-closures.go
func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

クロージャが参照する変数

クロージャが参照している変数は、一見ローカル変数のように見えますが、実際のところ破棄されるタイミングは異なります。
(というのも、Goのコンパイラが、クロージャに参照されている変数については、クロージャに属する変数として処理されるため)

通常のローカル変数 関数の実行が完了した時点
クロージャが参照する変数 何らかの形で参照され続ける限り、破棄されない

▼A Tour of Goより抜粋

Function-closures.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),
            neg(-2*i),
        )
    }
}

sumは、一見ローカル変数のように見えますが、クロージャから参照されているため、クロージャに属する変数として処理されます。

そのため、実行してみると以下のように
sumは前回の結果に+1を行なっているのがわかります。
つまり、adder()のクロージャが呼び出される毎にsumが新規で作成されている訳ではないことが確認できます。

また、posnegはそれぞれadder()を代入していますが、クロージャ間で値は共有されないことも確認できると思います。


実行結果
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90

参照

最後に

今までJavaを触れたことがあるくらいで
ちゃんとプログラミングを勉強したいと最近Goについて勉強を始めました!
Qiitaも慣れていないので、読み手にとって良い記事が書けているのか分からないことも多いですが、
間違っているやわかりづらいなどあれば、遠慮なくご指摘ご意見いただければ幸いです。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0