読者です 読者をやめる 読者になる 読者になる

don-bra.co

さいきんはphpとたわむれてます

Go Tourとクロージャとフィボナッチ数列

引き続き A Tour of Goを勉強中です。
Goのfunctionについてのところです。

A Tour of Go

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

サンプルコード

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),
        )
    }
}

実行すると

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

ふむふむ。posもnegもそれぞれsumを保持していて、実行するたびに
sum += x
されてるんだねーって理解しました。

しかし理解が浅かったため、次のexcersiceがちんぷんかんぷんに。

fibonacci (フィボナッチ)関数を実装しましょう。この関数は、連続するフィボナッチ数を返す関数(クロージャ)を返します。

考えても全くわからず、ググりました。

hamuhamu.hatenablog.jp

上のブログより引用してきたコードです。

package main

import "fmt"

func fibonacci() func() int {
    prev, next := 0, 1
    return func() int {
        prev, next = next, prev+next
        return next
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

ここであれってなったのが、なんで下の f() は引数をとらないの?
呼び出すごとに勝手に数字増えてるのはなんで?
ってなりました。

よく考えると f に代入されているのは func fibonacci の戻り値だから

return func() int {
        prev, next = next, prev+next
        return next
    }

なんですよね
で、prev, nextが保持されている(この表現でいいのかわからないですが)ので呼び出すごとにnextが増えていく。
関数が戻り値として代入されているっていうのがあまり無い感覚だったので、始め混乱しました。
なんとなくこの辺はjsっぽいなって後から思いました。

やっぱりきちんと噛み砕きながら進まないとどっかで詰まって困る訳でした。go tourは勉強になるなあ。。
まだまだ理解が足りないです。