プログラミング言語Goを読みながらメモ(第五章)

[プログラミング言語 Go]( https://www.amazon.co.jp/dp/4621300253 ) を読みながらメモ。

第一章 : https://qiita.com/Nabetani/items/077c6b4d3d1ce0a2c3fd
第二章 : https://qiita.com/Nabetani/items/d053304698dfa3601116
第三章 : https://qiita.com/Nabetani/items/2fd9c372fcd8383955a5
第四章 : https://qiita.com/Nabetani/items/59bfd00dc3323883a07f

で。

# 引数リスト

```go:go
package main

import "fmt"

func first(x int, _ int) int  { return x }
func second(x int, y int) int { return y } // y が未使用だけどエラーにならない

func main() {
	fmt.Println(first(1, 2))
	fmt.Println(second(1, 2))
}
```

上記の `second` は、未使用のローカル変数でエラーになるかと思っていたんだけど、ならない模様。未使用のローカル変数はエラーだけど、未使用の関数引数は OK らしい。

名前付き引数がないのはちょっと残念というか意外。

# 非標準パッケージの利用

5.2 で、`golang.org/x/net/html` という非標準パッケージを利用しているが、利用する方法が書いていない。まったくよろしくない。

利用するためには

```text
go get golang.org/x/net/html
```

を実行する必要がある。書いておいてほしい。

# 複数戻り値

> 多値呼び出しは、複数のパラメータを持つ関数呼び出しの唯一の引数として書くことが出来ます。

とあるので、多分駄目だろうと思いつつ試してみたのはこんなコード：

```go:go
package main

import (
	"fmt"
)

func main() {
	fmt.Printf(fmtAndValue())           //=> okay
	fmt.Printf("%d %s", intAndString()) //=> multiple-value intAndString() in single-value context
}

func fmtAndValue() (format string, value int) {
	return "%d", 123
}
func intAndString() (int, string) {
	return 456, "hoge"
}
```

やはり、唯一であることが重要。

ruby の splat 展開みたいなのがあると便利そうなんだけど、ないのかな。

あと空リターン。なんかパスカルっぽい。でも

>　空リターンは控えめに使うのが最善でしょう。

と、やや非推奨らしい。

# エラー処理戦略

まあ確かに C++やRubyの例外は難しい部分もあるけど、みんながちゃんと使えば幸せだと思うんだよなぁ。
という私の思いとは関係なく、 Go のエラー処理戦略は第二のリターンバリュー。
握りつぶしやすすぎるのが気になるけど、そこも狙いのひとつなんだと思ったり。

`log.Fatal` シリーズが面白い。

```go:go
package main

import (
	"fmt"
	"log"
)

func main() {
	log.Fatalln("hoge", "fuga", "piyo")
	fmt.Println("unreachable")
}
```

を実行すると

```text
2018/03/17 20:43:16 hoge fuga piyo
exit status 1
```

と出力される。

# 関数値

> 関数値はマップのキーとして使ってはいけません。

「いけません」と言われると試したくなる。

```go:go
package main

import "fmt"

func foo(int) int { return 1 }
func bar(int) int { return 2 }
func baz(int) int { return 3 }

func main() {
	a := make(map[func(int) int]int)
	fmt.Println(a) //=> invalid map key type func(int) int
	fmt.Println(foo == bar) //=> invalid operation: foo == bar (func can only be compared to nil)
}
```

エラーなので、いけませんというよりも「エラーになります」とかのほうが誤解がなくて良いと思った。

# 無名関数

```go:go
package main

import (
	"fmt"
)

func squares() func() int {
	x := 0
	return func() int {
		x++
		return x * x
	}
}

func main() {
	f := squares()
	g := squares()
	fmt.Println("f#1", f()) //=> f#1 1
	fmt.Println("f#2", f()) //=> f#2 4
	fmt.Println("f#3", f()) //=> f#3 9
	fmt.Println("g#1", g()) //=> g#1 1
	fmt.Println("g#2", g()) //=> g#2 4
	fmt.Println("g#3", g()) //=> g#4 9
}
```

`f` に閉じ込められている `x` と、`g` に閉じ込められている `x` では値が異なることを確認。当たり前だけど。

# ループ変数の補足

変数の寿命を捉えないと、クロージャを作るときに間違えやすい。

```go:go
package main

import "fmt"

var names = []string{"foo", "bar", "baz"}

func main() {
	var funcs []func()
	for _, n := range names {
		funcs = append(funcs, func() {
			fmt.Println(n)
		})
	}
	for _, f := range funcs {
		f()
	}
}
```

は、

```text
baz
baz
baz
```

を出力する。

python も同様だ。

```python3:python3.6
names = ["foo", "bar", "baz"]

funcs=[]
for n in names:
  funcs.append( lambda: print(n))
for f in funcs:
  f()
```

は、

```text
baz
baz
baz
```

を出力する。

一方 ruby は each 内で変数が毎回作られるので

```ruby:ruby
names = ["foo", "bar", "baz"]

funcs = []
names.each do |n|
  funcs.push(->(){ puts(n) })
end
for f in funcs do
  f[]
end
```

は

```text
foo
bar
baz
```

を出力する。

Go の場合は、スコープの狭い変数を作ることで解決する。
こんな具合：

```go:go
package main

import "fmt"

var names = []string{"foo", "bar", "baz"}

func main() {
	var funcs []func()
	for _, n := range names {
		n := n // 同名でも良い
		funcs = append(funcs, func() {
			fmt.Println(n)
		})
	}
	for _, f := range funcs {
		f()
	}
}
```

python の場合は、`for`ループの内側に変数を作ってもうまくいかない。
以下のように

```python3:python3
names = ["foo", "bar", "baz"]

funcs=[]
for n in names:
  funcs.append(lambda n=n: print(n))
for f in funcs:
  f()
```

`lambda` のデフォルト引数を悪用して束縛するとうまくいく。

# 可変長引数

`sum` とか `max` を見ると、C++ のようなテンプレートが欲しくなるね。我慢我慢。

# 遅延関数呼び出し

ようやく出てきた `defer`。

> 関数と引数の式は defer 文が実行されるときに評価されますが、実際の呼び出しは«中略»遅延されます。

すぐに評価されるってどういうこと？

```go:go
package main

import "fmt"

func foo() string {
	fmt.Print("<foo>")
	return "FOO"
}

func main() {
	defer fmt.Println(foo())
	fmt.Print("bar")
}
```

は、

```text
<foo>barFOO
```

を出力した。`defer` 文で `fmt.Println` は遅延されるけど、 `foo()` は遅延されない。そういうことか。

もうひとつ例を。

```go:go
package main

import "fmt"

func foo(s string) func() {
	fmt.Print("foo")
	return func() {
		fmt.Print(s)
	}
}

func main() {
	defer foo("bar\n")()
	fmt.Print("baz")
}
```

これは

```text
foobazbar
```

を出力する。

`defer` 文は、ブロックの最後ではなく、関数の最後に実行されるので

```go:go
package main

import "fmt"

func main() {
	fmt.Print("begin ")
	for i := 0; i < 3; i++ {
		// do something
		defer fmt.Printf("%d ", i)
	}
	fmt.Print("end ")
}
```

は

```text
begin end 2 1 0 
```

を出力する。
なるほど。長い関数を書くなというメッセージに見える。

まあ、無名関数を使って

```go:go
package main

import "fmt"

func main() {
	fmt.Print("begin ")
	for i := 0; i < 3; i++ {
		func() {
			// do something
			defer fmt.Printf("%d ", i)
		}()
	}
	fmt.Print("end ")
}
```

としてもいいんだけど。

あと。
こんな例はどうだろう：

```go:go
package main

import "fmt"

func main() {
	n := 10
	a := []byte{1, 2, 3}
	s := "hoge"
	defer fmt.Println(n, a, s)
	n += 100
	s = "fuga"
	a[0] = 100
}
```

これは

```text
10 [100 2 3] hoge
```

を出力した。つまり、defer は変数ではなく値を束縛しているように見える。
クロージャとは動きが違うところが面白い。クロージャの場合は変数を束縛するので下記の通りになる：

```go:go
package main

import "fmt"

func main() {
	n := 10
	a := []byte{1, 2, 3}
	s := "hoge"
	f := func() { fmt.Println(n, a, s) }
	n += 100
	s = "fuga"
	a[0] = 100
	f() //=>110 [100 2 3] fuga
}
```

`defer` とは動きが異なる。

# `panic` と `recover`

まずは普通に。

```go:go
```


`defer` の中に書くのが筋。
`defer` の外に書いても：

```go:go
package main

import "fmt"

func main() {
	fmt.Println("panic?", recover()) //=> panic? <nil>
	panic("hoge")
	fmt.Println("panic?", recover()) // 呼ばれない
}
```

意味がない。

ともあれ。
`panic` を自分で呼ぶことはあるかもしれないとおもう。
でも、(ある種の冗談や練習以外の理由で) `recover` を自分で呼ぶことはあまりなさそうな感じ。

次はオブジェクト指向の第六章 https://qiita.com/Nabetani/items/1c100394a65af6506187