【自己学習用】はじめてのGo3

# type

Goではtypeを用いて既存の型を拡張した独自の型を定義できる。
呼び出す際に，型が適合していないとコンパイルエラー。

```
type ID int
type Priority int

func ProcessTask(id ID, priority Priority) {
}

var id ID = 3
var priority Priority = 5
ProcessTask(priority, id) // コンパイルエラー
```

# 構造体（struct）
GOの構造体はメソッドを持つことができ，RubyやJavaでのクラスに近い。
構造体もtypeを用いて宣言し，構造体名のあとにそのフィールドを記述する。
各フィールドの可視性は名前で決まり，大文字で始まる場合はパブリック，小文字はプライベート。

```
type Task struct {
    ID int         // public
    Detail string  // public
    done bool      // private
}

func main() {
    var task Task = Task{
        ID: 1,
        Detail: "buy the milk",
        done: true,
    }
    fmt.Println(task.ID) // 1
    fmt.Println(task.Detail) // "buy the milk"
    fmt.Println(task.done) // true

    task := Task{} //構造体の生成時に値を明示的に指定しなかった場合は，ゼロ値で初期化
}
```

# コンストラクタ
Goにはコンストラクタがない。
代わりにNewで始まる関数を定義し，その内部で構造体を生成するのが通例。

```
func NewTask(id int, detail string) *Task {
    task := &Task{
        ID: id,
        Detail: detail,
        done: false,
    }
    return task
}

func main() {
    task := NewTask(1, "buy the milk")
    // &{ID:1 Detail:buy the milk done:false}
    fmt.Printf("%+v", task)
}
```

# メソッド
>型にはメソッドを定義できます。メソッドは，そのメソッドを実行した対象の型をレシーバとして受>け取り，メソッドの内部で使用できます。
**つまりいわゆる拡張メソッドのこと。**
func (メソッドを定義する型名の変数名, メソッドを定義する型名) メソッド名 戻り値 {
}


```
package main

import (
	"fmt"
)

type Task struct {
	ID     int
	Detail string
	done   bool
}

func NewTask(id int, detail string) *Task {
	task := &Task{
		ID:     id,
		Detail: detail,
		done:   false,
	}
	return task
}

func (task Task) String() string {
	str := fmt.Sprintf("%d) %s", task.ID, task.Detail)
	return str
}

func main() {
	task := NewTask(1, "buy the milk")
	fmt.Printf("%s", task.String()) // 1) buy the milk
}
```

# インタフェース
インタフェースの名前は，実装すべき関数名が単純な場合は，その関数名にerを加えた名前を付ける慣習がある。
Goは，型がインタフェースに定義されたメソッドを実装していれば，インタフェースを満たしているとみなす。
↑のTaskにはString()メソッドを実装しているため，Stringerを引数に取る次のような関数に渡すことができる。

```
type Stringer interface {
	String() string
}

～省略～

func main() {
	task := NewTask(1, "buy the milk")
	fmt.Printf("%s", task.String()) // 1) buy the milk

	Print(task) //　TaskにはStringメソッドを定義しているためエラーにならない
}

func Print(stringer Stringer) {
	fmt.Println(stringer.String())
}
```

次のような何も指定していないインタフェースを定義すると、どんな型も受け取ることができる関数を定義できる。
定義しなくてもinterface{}と記述すると同じ意味になる。

```
func Do(e Any) {
  // do something
}

Do("a") // どのような型も渡すことができる

func Do(e interface{}) {
  // do something
}

Do("a") // どのような型も渡すことができる
```

# 型の埋め込み
Goでは，継承はサポートされていない代わりに、ほかの型を「埋め込む」（⁠Embed）という方式で，構造体やインタフェースの振る舞いを拡張できる。

```
package main

import (
	"fmt"
)

type User struct {
	FirstName string
	LastName  string
}

func (u *User) FullName() string {
	fullname := fmt.Sprintf("%s %s",
		u.FirstName, u.LastName)
	return fullname
}

func NewUser(firstName, lastName string) *User {
	return &User{
		FirstName: firstName,
		LastName:  lastName,
	}
}

type Task struct {
	ID     int
	Detail string
	done   bool
	*User  // Userを埋め込む
}

func NewTask(id int, detail,
	firstName, lastName string) *Task {
	task := &Task{
		ID:     id,
		Detail: detail,
		done:   false,
		User:   NewUser(firstName, lastName),
	}
	return task
}

func main() {
	task := NewTask(1, "buy the milk", "Jxck", "Daniel")
	// TaskにUserのフィールドが埋め込まれている
	fmt.Println(task.FirstName)
	fmt.Println(task.LastName)
	// TaskにUserのメソッドが埋め込まれている
	fmt.Println(task.FullName())
	// Taskから埋め込まれたUser自体にもアクセス可能
	fmt.Println(task.User)
	fmt.Println(task.User.FirstName) //Userからもメンバにアクセス可能
	/*
	type Task struct {
		ID     int
		Detail string
		FirstName string
		done   bool
		*User  // Userを埋め込む
	}
	もしTaskにUser配下のメンバと同名のメンバがいたらどうなるか？
	→エラーとはならず共存する
	fmt.Println(task.FirstName)
	fmt.Println(task.User.FirstName)
	*/
}
```