【Golang】Structオリエンテッドまとめ

# 39 メソッドとポインタレシーバーと値レシーバー

### メソッド
#### 構造体の値を関数で使用する場合
```go
package main

import "fmt"

type Ver struct {
	X, Y int
}

func Area(v Ver) int {
	return v.X * v.Y
}

func main() {
	v := Ver{3, 4}
	fmt.Println(Area(v))
}
```

```
12
```

Area()と構造体Verに結びつきがない

### 値レシーバー
オブジェクト指向のクラスとメソッドのように、構造体のメソッドのような形が作れる

```go
package main

import "fmt"

type Ver struct {
	X, Y int
}

func (v Ver) Area() int {
	return v.X * v.Y
}

func main() {
	v := Ver{3, 4}
	fmt.Println(v.Area())
}
```

```
12
```

### ポインタレシーバー
```go
package main

import "fmt"

type Ver struct {
	X, Y int
}

func (v Ver) Area() int {
	return v.X * v.Y
}

func (v *Ver) Scale(i int) {
	v.X = v.X * i
	v.Y = v.Y * i
}

func main() {
	v := Ver{3, 4}
	v.Scale(10)
	fmt.Println(v.Area())
}
```
```
1200
```
メソッドの構造体名にアスタリスクをつけることで、構造体の中身を書き換えることができる

# 40 コンストラクタ
外にあるpackageを呼び出すやり方
ストラクトに定義した値を大文字ではなく小文字にすると、packageの外から編集することができなくなる

```go
package main

import "fmt"

type Ver struct {
	X, Y int
}

func (v Ver) Area() int {
	return v.X * v.Y
}

func (v *Ver) Scale(i int) {
	v.X = v.X * i
	v.Y = v.Y * i
}

func New(x, y int) *Ver {
	return &Ver{x, y}
}

func main() {
	v := New(3, 4)
	v.Scale(10)
	fmt.Println(v.Area())
}
```
New()を使用することで、他のpackageから生成したpackageを呼び出すときに使用するv

# 41 Embedded
クラスの継承のようなもの
```go
package main

import "fmt"

type Ver struct {
	X, Y int
}

func (v Ver) Area() int {
	return v.X * v.Y
}

func (v *Ver) Scale(i int) {
	v.X = v.X * i
	v.Y = v.Y * i
}

type Ver3D struct {
	Ver
	Z int
}

func (v Ver3D) Area3D() int {
	return v.X * v.Y * v.Z
}

func (v *Ver3D) Scale(i int) {
	v.X = v.X * i
	v.Y = v.Y * i
	v.Z = v.Z * i
}

func New(x, y, z int) *Ver3D {
	return &Ver3D{Ver{x, y}, z}
}

func main() {
	v := New(3, 4, 5)
	v.Scale(10)
	fmt.Println(v.Area3D())
}
```

# 43　インターフェースとダックタイピング
インターフェースはPHPのものとほぼ同様
```go
package main

import "fmt"

type Human interface {
	Say()
}

type Person struct {
	Name string
}

func (p *Person) Say() {
	p.Name = "Mr." + p.Name
	fmt.Println(p.Name)
}

func main() {
	var mike Human = &Person{"Mike"}
	mike.Say()
}

```

Humanインターフェースを実装した変数mikeにアンパサンドをつけたPersonを代入する

```go
package main

import "fmt"

type Human interface {
	Say() string
}

type Person struct {
	Name string
}

func (p *Person) Say() string {
	p.Name = "Mr." + p.Name
	return p.Name
	// fmt.Println(p.Name)
}

func DriveCar(human Human) {
	if human.Say() == "Mr.Mike" {
		fmt.Println("Run")
	} else {
		fmt.Println("Get out")
	}
}

func main() {
	var mike Human = &Person{"Mike"}
	mike.Say()
}
```
インターフェースを実装することにより、呼び出される側に呼び出す側によって条件を分岐する処理を追加しない。
これをダックタイピングという(オブジェクト指向の本の復習)

# 44 タイプアサーションとswitch type
```go
package main

import "fmt"

func do(i interface{}) {
	ii := i.(int)
	i = ii * 2
	fmt.Println(i)
}

func main() {
	do(10)
}
```
関数の引数にinterfaceを指定すると、どんな型でも受け取る事ができる。
ただ、
```go
ii := i.(int)
```
のように型を設定してやらないとエラーとなる
これをタイプアサーションという

```go
package main

import "fmt"

func do(i interface{}) {
	switch v := i.(type) {
	case int:
		fmt.Println(v * 2)
	case string:
		fmt.Println(v + "!")
	}
}

func main() {
	do(10)
	do("aaaa")
}
```
型によって分岐をする場合、switch文を使用する。

# 45 Stringer
```go
package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func (p Person) String() string {
	return fmt.Sprintf("My name is %v.", p.Name)
}

func main() {
	mike := Person{"Mike", 22}
	fmt.Println(mike)
}
```
```go
My name is Mike.
```

ストラクトにString()を実装すると、Printlnで出力する際のフォーマットを変更することができる

# 46 カスタムエラー
```go
package main

import "fmt"

type UserNotFound struct {
	Username string
}

func (e *UserNotFound) Error() string {
	return fmt.Sprintf("User not found: %v", e.Username)
}

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

func main() {
	if err := myFunc(); err != nil {
		fmt.Println(err)
	}
}
```