Golang 基礎 (struct周り)part2

[part1](https://qiita.com/mi11km/items/ea76eeba32bff67b17a5)の続き

## makeとnewの違い
どちらも値を入れずメモリ領域を確保する。違いはポインタが返ってくるかどうか。

```golang
// 返ってこない
s := make([]int, 0)
m := make(map[string]int)
ch := make(chan int)

// 返ってくる
var p *int = new(int)
var st = new(struct{})
```

cf.　中身はnil (メモリ確保していない)

```golang
var s []int
var m map[string]int
var ch chan int
var p *int 
```

## struct
```golang
type Vertex struct {
	X, Y int
	S string
}
```
v1とv2は同じ意味。v3とv4は同じ意味。

```golang
v1 := Vertex{} // {0 0  }
var v2 Vertex // {0 0  }

v3 := new(Vertex) // &{0 0  }
v4 := &Vertex{} // &{0 0  }
```

```golang
	changeVertex := func(v Vertex) {
		v.X = 1000
	}
	changeVertex2 := func(v *Vertex) {
		v.X = 1000 // (*v).X = 1000 と同じ意味になる
	}

	v := Vertex{1, 2, "test"}

	changeVertex(v) // 値渡し
	fmt.Println(v) // {1 2 test} 値が書き換わっていない
	changeVertex2(&v) // 参照渡し
	fmt.Println(v) // {1000 2 test} 値が書き換わっている
```

## structオリエンテッド
```golang
package main

import "fmt"

type Vertex struct {
	x, y int // 先頭が小文字だとpackage内からのみ参照可能
}

// メソッド（値レシーバー）
func (v Vertex) Area() int {
	return v.x * v.y
}

// メソッド（ポインタレシーバー）　中身を書き換える！
func (v *Vertex) Scale(i int) {
	v.x = v.x * i
	v.y = v.y * i
}

// Embedded(継承みたいなやつ)
type Vertex3D struct {
	Vertex
	z int
}

func (v Vertex3D) Area3D() int {
	return v.x * v.y * v.z
}

func (v *Vertex3D) Scale3D(i int) {
	v.x *= i
	v.y *= i
	v.z *= i
}

// コンストラクタ
func New(x, y, z int) *Vertex3D {
	return &Vertex3D{Vertex{x, y}, z}
}

func main() {
	v := New(4, 5, 6)
	v.Scale3D(10)
	fmt.Println(v.Area()) // 継承元のメソッドも使える
	fmt.Println(v.Area3D())
}
```

## non-struct
自分なりの型とメソッドを作れる。

```golang
type MyInt int

func (i MyInt) Double() int {
	return int(i * 2)
}
```

## インターフェースとダックタイピング
```go
package main

import "fmt"

// 設計書みたいなイメージ
type Human interface {
	Say() string // 実装しないといけない関数を書く
}

type Person struct {
	Name string
}

func (p Person) Say() string {
	return "Mr." + p.Name
}

// インターフェースのダックタイピング(Say()というメソッドがないと成立しないときに使う)
func DriveCar(human Human) {
	if human.Say() == "Mr.Mike" {
		fmt.Println("Run")
	} else {
		fmt.Println("Get out")
	}
}

func main() {
	var mike Human = Person{"Mike"} // Humanにstructを入れたら、Say()というメソッドがないとだめ
	DriveCar(mike)
}
```

## タイプアサーションとswitch type文
```golang
// 引数が interface{} →何でも引数として受け入れる！
func do(i interface{})  {
	/* タイプアサーション: interfaceを他の型に変える
	ii := i.(int)
	ss := i.(string) など
	*/

	// switch type 文
	switch v := i.(type) {
	case int:
		fmt.Println(v * 2)
	case string:
		fmt.Println(v + "!!!!")
	default:
		fmt.Printf("I don't know %T.\n", v)

	}
}
```

## Stringer
```golang
package main

import "fmt"

type Person struct {
	Name string
	Age int
}

// String()のメソッドを実装すれば fmt の出力を変えることができる！
func (p Person) String() string {
	return fmt.Sprintf("My name is %v, I'm %v years old.", p.Name, p.Age)
}

func main() {
	mike := Person{"Mike", 20}
	fmt.Println(mike) // My name is Mike, I'm 20 years old.
}
```

## カスタムエラー
```golang
package main

import "fmt"

// 自分なりのエラーを作る
type UserNotFound struct {
	Username string
}

// 作ったエラーにError()のメソッドを実装するとエラー時にこれが出力される
func (e *UserNotFound) Error() string {
	return fmt.Sprintf("User not found: %v", e.Username)
}

func myFunc() error {
	// something wrong
	ok := false
	if ok {
		return nil
	}
	return &UserNotFound{Username: "mike"}
}


func main() {
	if err := myFunc(); err != nil{
		fmt.Println(err) // User not found: mike
	}
}
```

Error()をポインタレシーバーにする理由：エラーが違う場所で起きたときに比較判定するため。
以下サンプルコード。err == io.EOFの部分。
err == errors.New("EOF")としてもうまく行かない。→　r.Read()が io.EOFというエラーを返すため。

```golang
package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	r := strings.NewReader("Hello, Reader!")

	b := make([]byte, 8)
	for {
		n, err := r.Read(b)
		fmt.Printf("n=%v err=%v b=%v\n", n, err, b)
		fmt.Printf("b[:n]=%q\n", b[:n])
		if err == io.EOF{
			break
		}
	}
}
```

## 参考
[現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発](https://www.udemy.com/course/go-fintech/)

[part3](https://qiita.com/mi11km/items/25f66a9865f37afdc95b)へ