A Tour of Go メモ ~Methods and interfaces~

## はじめに

Go の勉強のため、[A Tour of Go](https://go-tour-jp.appspot.com/methods/1)に取り組んでいる
今回は`Methods and interfaces`章について、学んだことを記していく

まとめ記事は[こちら](https://qiita.com/eyuta/items/77ac58e4d9141898c733)

## 使えそうなスニペット

※筆者は VSCode を使用

### `meth`

method を作成する。すごい便利

```go
func (receiver type) method()  {

}
```

### `tyi`

```go
type name interface {

}
```

## ページごとの補足

### Methods and pointer indirection

struct と\*struct の違いを調べておきたい

### The empty interface

使いみち

Typescript における`unknown`に近い？

### Type assertions

使いみち

```go
var i interface{} = "Hello"
s, ok := i.(int) // no panic
```

```go
var i interface{} = "Hello"
s := i.(int) // panic
```

### Exercise: Stringers

```go
func (ip IPAddr) String() string {
	return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[3])
}
```

マジックナンバーを使わない場合、こんな感じになりそう

```go
func (ip IPAddr) String() string {
	stringArray := make([]string, 0, len(ip))
	for _, i := range ip {
		stringArray = append(stringArray, fmt.Sprint(i))
	}
	return strings.Join(stringArray, ".")
}
```

### Errors

関数の返り値の型に`error`を指定した場合、return した値の`Error()`メソッドが実行される

### Exercise: Errors

naked return ステートメントが便利
error の初期値に nil が勝手に入ってくれる

```go
type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("Error: %v", float64(e))
}

func Sqrt(x float64) (z float64, e error) {
	if x < 0 {
		e = ErrNegativeSqrt(x)
		return
	}
	z = 1
	for i := 0; i < 10; i++ {
		z -= (z*z - x) / (2 * z)
	}
	return
}

func main() {
	fmt.Println(Sqrt(2))  // 1.414213562373095 <nil>
	fmt.Println(Sqrt(-2)) // 0 Error: -2

}
```

### Exercise: Readers

一応バリデーションは通ったが、こんな実装で良いか不明
他の人の回答を見ると、`strings.NewReader`を使わずにシンプルに byte スライスに`A`を挿入していた
それでいいのか……

```go
type MyReader struct{}

func (m MyReader) Error() string {
	return fmt.Sprint("Error!")
}

func (m MyReader) Read(b []byte) (int, error) {
	var a string
	for i := 0; i < len(b); i++ {
		a += "A"
	}
	r := strings.NewReader(a)

	for {
		_, err := r.Read(b)
		if err == io.EOF {
			break
		}
	}
	return len(b), nil
}
```

### Exercise: rot13Reader

実装自体は単純
ただ、`変換後の文字列をどう返せばいいのか`悩んだ
`Read`の引数に渡ってくる byte に文字を格納することで、その文字列が返る

また、13 を足すか引くかを元々数字で判断していた(`b < 65`のように)
しかし、`rune`を使うことで、直感的に書くことができる
※ただし、これができるのは一部の文字だけ。日本語は NG

```go
func rot(b byte) byte {
	const ROT = 13
	switch {
	case b < 'A':
		return b
	case b < 'N':
		return b + ROT
	case b < 'a':
		return b - ROT
	case b < 'n':
		return b + ROT
	case b <= 'z':
		return b - ROT
	default:
		return b
	}
}

func (r *rot13Reader) Read(b []byte) (n int, err error) {
	n, err = r.r.Read(b)
	if err != io.EOF {
		for i := range b {
			b[i] = rot(b[i])
		}
	}
	return n, err
}

func main() {
	s := strings.NewReader("Lbh penpxrq gur pbqr!")
	r := rot13Reader{s}
	io.Copy(os.Stdout, &r)
}

```

### Exercise: Images

struct 初期化時に表示計算用の関数`fn`を与えるようにしてみた

```go
package main

import (
	"fmt"
	"image"
	"image/color"

	"golang.org/x/tour/pic"
)

type MyImage struct {
	x0, y0, x1, y1 int
	fn             func(x, y int) int
}

func (m MyImage) At(x, y int) color.Color {
	v := uint8(m.fn(x, y))
	return color.RGBA{v, v, 255, 255}
}
func (m MyImage) Bounds() image.Rectangle {
	return image.Rect(m.x0, m.y0, m.x1, m.y1)
}
func (m MyImage) ColorModel() color.Model {
	return color.RGBAModel
}

func main() {
	fn := func(x, y int) int { return x - y }
	m := MyImage{0, 0, 100, 100, fn}
	fmt.Println(m.Bounds())
	fmt.Println(m.At(0, 0).RGBA())
	pic.ShowImage(m)
}
```