[Go]メソッド

# 概要

* [前回](https://qiita.com/hasesiu/items/993a2e20c70219f016e2)の続き
* 今回はメソッドについて学習
    * 教材を読むに、次のインターフェースと合わせて、特に重要な単元のようだ。

参考

https://www.oreilly.co.jp/books/9784814400041/#

# メソッド

* ユーザ定義の型に付随する関数としてメソッドが定義できる
* `func (レシーバ) メソッド名(引数） 戻り値`の形式
    * 関数にレシーバが追加されている。レシーバは紐付けるユーザ定義型のこと
    * Javaとは異なり、オブジェクトとは別の場所で定義しており、紐付にレシーバを使っている。
    * また、オーバロードはできないため、一つのレシーバに対して同じメソッド名は複数定義できない

```go
// ユーザ定義型（構造体）
type Person struct {
	name string
	age int
}
// メソッド
func (p Person) toString() string {
	return fmt.Sprintf("%s: %d歳", p.name, p.age)
}

func main() {
	person := Person {
		name: "test",
		age: 30,
	}
	// メソッドの実行
	fmt.Println(person.toString())
}
```

## ポインタ型と値型レシーバ

* ポインタ型レシーバは、レシーバが変更される場合に指定する
* 値型レシーバは、レシーバを変更しない
    * 関数の引数のポインタと同じ考え
* ユーザ定義型に対するメソッドの内、ポインタ型レシーバがひとつでもあれば、他のメソッドもポインタ型レシーバにする必要がある。
    * →何故そうする必要があるのか？ひとまず、そういるルールとして覚えておくか。

```go
type Counter struct {
	total int
	updated time.Time
}

// ポインタ型レシーバ
func (c *Counter) Incremament() {
	c.total++
	c.updated = time.Now()
}

func main() {
	var c Counter
	c.Incremament() // 暗黙的にポインタ値に変換されるため、&cではなくてOK
}
```

## メソッド値とメソッド式

* メソッド値：メソッドを変数に格納できる（=第一級オブジェクト）
* メソッド式：型から関数を作成できる。`func(レシーバ, 引数) 戻り値型`。第一引数にはメソッドのレシーバを設定する。`

```go
type Adder struct {
	value int
}
func (a Adder)AddTo(val int)int {
	return a.value + val
}

func main() {
	myAdder := Adder{value: 10}
	// メソッド値
	f1 := myAdder.AddTo
	fmt.Println((f1(20)))

	// メソッド式
	f2 := Adder.AddTo
	fmt.Println(f2(myAdder,25))
}
```

## iota

* Goは列挙型はなく、代わりにiotaというものがある。
* iota：増加する値を一連の定数に割り当てることができる。
* `const (定数名 型=iota)`を指定し、2行目以降は定数名を列挙

```go
// 型を定義
type Category int

// iota値は0からの連番
const (
	Cate1 Category = iota //0
	Cate2	//1
	Cate3	//2
)
```

## 埋め込みによる合成

* Goには継承がないが、代わりに合成や昇格が組み込まれており、これを使用して、コードの再利用性を推奨している。
* 昇格
    * 下位の構造体を、上位の構造体のフィールドを埋め込むと、下位の構造体は上位の構造体に昇格する。
    * 昇格すると、上位の構造体から直接呼び出すことができる

```go
// 下位の構造体
type Employee struct {
	name string
	id string
}
func (e Employee) Description() string {
	return fmt.Sprintf("%s(%s)", e.name, e.id)
}

// 上位の構造体
type Manager struct {
	Employee //昇格：下位の型のみを書く。型のフィールドが加わる。
	Reports []Employee
}
func (m Manager) addEmpoyees() []Employee {
	newEmployees := []Employee{
		{"太郎","100"},
		{"治郎","200"},
	}
	return newEmployees
}

func main() {
	m := Manager{
		Employee: Employee{"花子", "000"},
		Reports: []Employee{},
	}
    // 下位の型のフィールド、メソッドを呼び出せる
	fmt.Println(m.id) // 000 
	fmt.Println(m.Description()) //000(花子)

	m.Reports = m.addEmpoyees()
	fmt.Println(m.Employee) // {花子 000}
	fmt.Println(m.Reports)	// [{太郎 100} {治郎 200}]	
}
```

## 埋め込みと継承の違い

* 埋め込みをサポートしている言語はGo言語だけらしい
* 継承とは異なり、サブクラス（上記のManager）を、親クラス（上記のEmployee）に代入できない。
    * ※説明のためにサブクラス、親クラスとしたが、継承ではないので実際は違う。
* 具象型には、動的ディスパッチが存在しない
    * 実行時の型によって呼び出し先が変わること。
    * オーバライドやポリモーフィズムの仕組みが働かないということ？

```go
type Inner struct {
	A int
}

func (i Inner) IntPrinter(val int) string {
	return fmt.Sprintf("Inner: %d", val)
}

func (i Inner) Double() string {
	result := i.A * 2
	// ここで呼び出されるのは、innerのIntPrinter
	return i.IntPrinter((result))
}

type Outer struct {
	Inner // 埋め込み
	S string
}

func (o Outer) IntPrinter(val int) string {
	return fmt.Sprintf("Outer: %d", val)
}

func main() {
	o := Outer{
		Inner: Inner{
			A: 10,
		},
		S: "Hello",
	}
	fmt.Println(o.Double()) //Inner: 20
}
```

# 終わりに

* メソッドは構造体の内部で定義するのではなく、外部で定義する。その際に構造体をレシーバとして紐づけている。
    * この辺りの構文の違いから、明確にオブジェクト指向とは違うのだと感じた。
* 埋め込みは継承と異なり、型の互換性はない。オーバライドやポリモーフィズムもなさそう。（言及はされていなかったので不明）
    * Javaなどのコンポジション（has-a関係）とも違うのだろうか。
* メソッド、埋め込み（合成）は、Goの独自色が強いと感じた。（Java等のオブジェクト指向との共通点をあまり感じなかった。）
* そのため、本単元をいまいち理解しきれていない。次のインターフェースでも引き続き本単元の内容を利用するようなので、そこで理解を深めたい。