golang 関数（func）の引数や戻り値で関数を指定したときの動作

# はじめに
golang を使い始めたのですが、関数の使い方で躓いたのでメモを残そうと思います！
関数の引数や戻り値に変数（int、string等）を指定した場合の挙動は想像できるのですが、 引数や戻り値に `func(int)` のような関数を指定をしたときの動きが直ぐにわからず、、動作を確認しました。

#### 確認パターン

 - 引数に関数
 - 戻り値に関数

# 引数に関数(1)
簡単な足し算をする処理です。 関数 `calc` の第１引数を `func(int, int)` とし、関数を受け取れるようにしています。
どの順番で実行されたかを確認するために `println` を入れています。

```golang
package main

import (
	"fmt"
)

func calc(fn func(int, int) int, x int, y int) (res int) {
	fmt.Println("(A)")
	res = fn(x, y) // 関数：add を実行
	return
}

func add(x int, y int) int {
	fmt.Println("(B)")
	return x + y
}

func main() {
	fmt.Println(calc(add, 1, 2))
}
```

処理結果

```
(A)
(B)
3
```

次のことが分かりました。

 - `main` から `calc(add, a, b)` を呼んだときに実行されるのは関数 `calc` である（当たり前ですが、、）。
 - `calc` の中で `res = fn(x, y)`を実行したときに 関数 `add` が実行される。
 - 引数を `fn func(int, int)` とし、呼び出すときに `calc(add, a, b)` のように `add` を指定しているので、変数`fn` の中身は `add` になる。
 - 関数 `add` の戻り値で計算結果 3 を 関数 `calc` に返し、関数 `calc` はその値を、main に返している。

# 引数に関数(2)
次は足し算と引き算をする処理を見ていきます。

```golang
package main

import "fmt"

func calc(x int, y int, fn func(int, int) int) int {
	fmt.Println("(A)")
	return fn(x, y) // 関数:add or sub どちらかを実行
}

func add(x int, y int) int {
	fmt.Println("(B)")
	return x + y
}

func sub(x int, y int) int {
	fmt.Println("(C)")
	return x - y
}

func main() {
	resAdd := calc(1, 2, add)
	fmt.Println(resAdd)
	fmt.Println("-------------")

	resSub := calc(5, 4, sub)
	fmt.Println(resSub)
}
```

処理結果

```
(A)
(B)
3
-------------
(A)
(C)
1
```

 - 呼び出す時の引数により実行される関数が変わる。main から `calc(1, 2, add)` を指定した場合は、関数 `add` が実行され、`calc(5, 4, sub)` を指定した場合は、関数 `sub` が実行された。
 - 関数 `calc` の引数を `fn func(int, int) int` としている。この時点では何の関数が実行できるかは関数 `calc` 自身も分かっていない。同じ型の関数、且つ、呼び出し可能な関数であれば、何でも受け取ることを表す。つまり、呼び出し時のパラメータにより柔軟に呼び出す関数を変えることが可能となる。

# 戻り値が関数(1)
戻り値が関数になっている場合を確認します。
関数 `func1` の戻り値を `func()` としました。

```golang

package main

import "fmt"

func func1(n string) func() {
	fmt.Println(n)
	return func() {
		func2("(B)")
	}
}

func func2(n string) {
	fmt.Println(n)
}

func main() {
	_ = func1("(A)")
}
```

処理結果

```
(A)
```

 - main にて `func1("(A)")` としている通り、関数 `func1` が呼び出される。
 - 関数 `func1` では受け取ったパラメータを元に `(A)` を出力。
 - 関数を返す必要があるため `return func()` としている。
 - この場合、関数 `func2` は実行されない。

# 戻り値が関数(2)
関数 `func2` が実行されるように変更します。

```golang
package main

import "fmt"

func func1(n string) func() {
	fmt.Println(n)
	return func() {
		func2("(B)")
	}
}

func func2(n string) {
	fmt.Println(n)
}

func main() {
	f := func1("(A)")
	fmt.Println("-----------")
	f()
}
```

処理結果

```
(A)
-----------
(B)
```

 - main を `f := func1("(A)")` にし、戻り値である `func()` を受け取る。関数 `func1` が呼び出されただけでは 関数 `func2` は実行されていない。
 - main にて `f()` を実行。これにより、関数 `func1` の `func2("(B)")` がはじめて実行される。

# 戻り値が関数(3)
違うパターンを見てみます。

```golang
package main

import "fmt"

func func1(n string) func() {
	fmt.Println(n)
	return func2("(B)")
}

func func2(n string) func() {
	fmt.Println(n)
	return func() {
		fmt.Println(n)
	}
}

func main() {
	f := func1("(A)")
	fmt.Println("-----------")
	f()
}
```

処理結果

```
(A)
(B)
-----------
(B)
```

 - 関数 `func1` の戻り値を `return func2("(B)")` としたことで、main から `f := func1("(A)")` が呼び出されたタイミングで関数 `func2` も実行されるようになった。また、この時点では関数 `func2` の return内の関数は実行されていないことが分かる。
 - main にて `f()` を実行することで、関数 `func2` のreturn内の関数が実行される。また最初に `func2` が呼び出された時の変数を保持しているため `(B)` が出力された。