エンジニアもどきの雑記

メモ帳です。きっと。macアプリ配信windowsでもできるようになるまで絶対にメイン機にしないマン。特筆しない限り環境は【win10home,i5-7200u,8g,64bit,巨乳が好き】

GoLangやるpart4

前回
dddpga1.hateblo.jp

前回の最後でちょろっと触れた関数について踏み込む。

無名関数


jsでよく見るあの形がある。

main.go

package main

import "fmt"

func main() {
        plus := func(x, y int) int { return x + y }
        res := plus(1, 2)
        fmt.Println(res)
}


関数名のない関数。
値みたいに引数にしたり変数に入れたりして扱うアレ。

[(゜-゜):daichi]@:sample$ go run main.go
3


関数を返す関数

main.go

package main

import "fmt"

func returnFunc() func() {
        return func() {
                fmt.Println("hoge")
        }
}

func main() {
        f := returnFunc()
        f()
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
hoge


func returnFunc() func() {...
返り値の型のfunc()がすっごいわかりづらいけどこれは他の関数と同じであくまで
返り値の型。func()(関数)を返すよって指定。


関数が引数の関数

main.go

package main

import "fmt"

func argFunc(f func()) {
        f()
}

func main() {
        argFunc(func() {
                fmt.Println("hoge")
        })
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
hoge


無名関数をargFuncに渡してあげてfに代入してargFuncで実行させる。
渡してる関数は表示だけの返り値の型がないので記述なし。


クロージャ

goの無名関数はクロージャ
クロージャとは→なぜクロージャ(Closure)と言うのか? - Qiita

例(本のほぼそのままだけどこれがわかりやすい。。。
main.go

package main

import "fmt"

func delay() func(string) string {
        var store string

        return func(next string) string {
                s := store
                store = next
                return s
        }
}

func main() {
        f := delay()

        fmt.Println(f("1"))
        fmt.Println(f("2"))
        fmt.Println(f("3"))
        fmt.Println(f("4"))
        fmt.Println(f("5"))
}


実行

[(゜-゜):daichi]@:sample$ go run main.go
    ←ここが空
1
2
3
4


結果として、一個ずつ遅れて表示されている。

func main内でdelay()を実行しているのは今まで通り。
では、delay()ではどうなってるか。

func delay() func(string) string {
        var store string

        return func(next string) string {
                s := store
                store = next
                return s
        }
}


delay()にはstringを引数にとり、string型の値を返す無名関数が指定されてる。
この書き方は返り値を指定できるあれ、だよね? あってる?
delay()の(無名関数の)local変数としてvar store stringを宣言。

返却しているのが

 return func(next string) string {
        s := store
        store = next
        return s
}


この部分がクロージャ。だよね?
通常、delay()のlocal変数であるstoreは一回ごとに破棄されるはず? だけど
このクロージャに参照され続けることによって値が保持され続けてる。
とのこと。

ここら辺なんとなくはわかってるんだど書き方から流れから細かく説明できない力不足。

で、このクロージャを使ってできるのがジェネレータ。
これはphp仕事にしてるんで流石にわかる。

main.go

package main

import "fmt"

func delay() func() int {
        i := 0

        return func() int {
                i += 1
                return i
        }
}

func main() {
        f := delay()

        fmt.Println(f())
        fmt.Println(f())
        fmt.Println(f())
        fmt.Println(f())
        fmt.Println(f())
}


先ほどのmain.goを少し書き換える。

[(゜-゜):daichi]@:sample$ go run main.go
1
2
3
4
5



とりあえず今日はここまで。
関数のlocal変数をクロージャ内で参照すると値を保持したままにできる。
ってことで。

次回は定数とinterfaceか、定数と参照型やりたい。それぞれ順番かも。

次回
dddpga1.hateblo.jp