embeded使い方【golang】

# embeded
- golangで継承のようなことをしたいときに使うembeded
- イマイチ理解できなかったのでまとめました。
- Javaなどのオブジェクト指向言語の継承と同じ使い方をすると`スーパークラスとして初期化する際のエラー`や`オーバーライドできない`などの問題が発生する
- ※キャプチャと本記事のコードとで初期化時の値が異なることがありますが本質的なところは変わらないのでご了承ください。

# embededの例
- まずは構造体に何らかのメソッドを持たせる
- Employees（従業員）とBoss（上司）にしてみる

```go:main.go
type Employees struct {
    name string
}

func newEmployees(n string) *Employees {
    e := new(Employees)
    e.name = n
    return e
}

func (e *Employees) Hello() string {
    return "名前：" + e.name  // >>
}
```

- これに部長という意味で`Boss`という構造体を加えてみる

```go:main.go
type Boss struct {
  Employees  // embeded
  age string  // Staff独自のフィールドを持たせるとする
}

func newBoss(n, a string) *Boss{
  b := new(Boss)
  b.name = n
  b.age = a
  
  return b
}

```

- ↑の書き方で、`Boss`は`Employees`の持ち物（フィールド、メソッド）を**貰う（委譲）**することができる
- これまでのソースをまとめて、試しに以下のように`Employees`と`Boss`を初期化してそれぞれのインスタンスでメソッド`Hello`を呼んでみる

```go:main.go
package main

import "fmt"

type Employees struct {
    name string
}

func newEmployees(n string) *Employees {
    e := new(Employees)
    e.name = n
    return e
}

func (e *Employees) Hello() string {
    return "名前：" + e.name  // >>
}

type Boss struct {
  Employees  // embeded
  age string  // Boss独自のフィールドを持たせるとする
}

func newBoss(n, a string) *Boss{
  b := new(Boss)
  b.name = n
  b.age = a
  
  return b
}

func main() {
    employee := newEmployees("従業員A")
    boss := newBoss("部長A ", "11")
    fmt.Println(employee.Hello())
    fmt.Println(boss.Hello())
}

```

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/6ece0e9d-5d69-2560-462c-9d11580ef1f9.png)


- この時点では`継承`のそれと同じ動作のように見える
- 次にオーバーライドができるか。以下のように年齢も出力するHelloメソッドを追加
- Bossは年齢も持っているため年齢も出してみる

```go:main.go
func (b *Boss) Hello() string {
    return b.name + b.age
}
```

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/cf864311-c4ea-13e5-a893-e69b0e986d67.png)


- それぞれの`Hello`メソッドの内容が出力されているのでこれも想定通りのオーバーライド


- ではではJavaで言うところのスーパークラス型の変数への代入はどうか
- Employees型の変数にBossのインスタンスを入れるイメージで書いてみる


```go:main.go
var e *Employees
e = newBoss("従業員B","11")


// Javaで書くと
// Boss b = new Boss("従業員B","11");
// Employees e = b;
```

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/72f4a263-5086-32ed-1b00-d66f9d281b42.png)

# ダメでしたー
- golangでは`「子型 is a 親型」`は使えないみたい

# Bossでの構造体の初期化
```go:main.go
boss := &Boss{name: "従業員C", age: "10"}
```
- これだとエラーになります

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/cf3d60bc-2ffd-99e7-2146-77a7fdec6f40.png)


- 正しくは以下のようにするそうです

```go:main.go
boss := &Boss{
    Employees: Employees{name: "従業員C"}, 
    age: "10"
}
```

- このことから何がわかるかと言うと、BossはEmployees型を持っているということ

# オーバーライドの仕方
- 今までの検証でわかるようにBossはEmployeesを`継承`しているわけではなく**BossがEmployeesを持っている**ということだったのがわかりました。なので、**継承してメソッドをオーバーライドするぞー**としてもオーバーライドしてくれません。

- 例：Helloを使った別のメソッドを作成して呼んでみる

```go:main.go
func (e *Employees) SignUp() string {
    return e.Hello() + "で登録"
}
```
- 全体

```go:main.go
package main

import "fmt"

type Employees struct {
    name string
}

func newEmployees(n string) *Employees {
    e := new(Employees)
    e.name = n
    return e
}

func (e *Employees) Hello() string {
    return "名前：" + e.name
}

type Boss struct {
  Employees  // embeded
  age string  // Boss独自のフィールドを持たせるとする
}

func newBoss(n, a string) *Boss{
  b := new(Boss)
  b.name = n
  b.age = a
  
  return b
}

func (b *Boss) Hello() string {
    return b.name + b.age
}

func (e *Employees) SignUp() string {
    return e.Hello() + "で登録"
}

func main() {
    employee := newEmployees("従業員A")
    boss := newBoss("部長A ", "11")
    fmt.Println(employee.Hello())
    fmt.Println(boss.Hello())
}
```

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/06e36bac-0c96-f47a-4f06-8a004732d9bf.png)


- オーバーライドしたはずなのにBossのHelloに書いた年齢が出力されない。。。
- これは結局のところ、両方のHelloメソッドともにEmployeesのものということです。

# ポリモーフィズムを実現するには？？
- `ポリモーフィズム`：引数を受け取ったインスタンスがクラスによって違う振る舞いをすること
- golangでポリモーフィズムを実現するには`embeded`と`interface`を使用するらしい

### インタフェースを定義する

```go:main.go
type Person interface {
    Hello() string
}
```

- `Person`にHelloメソッドを持っているインスタンスを格納していくイメージ
- SignUpはこの`Person`を引数に受け取るようにする

```go:main.go
func SingUp(p Person) string {
    return p.Hello()  + "で登録"
}
```

- で、mian.goで呼び出し

```go:main.go
func main() {
    ps := []Person{
        newEmployees("従業員A")
        newBoss("部長A ", "11"),
    }
    for _, p := range ps {
        fmt.Println(SignUp(p))
    }
}
```

### 全体はこう

```go:main.go
package main

import "fmt"

type Person interface {
    Hello() string
}

type Employees struct {
    name string
}

func newEmployees(n string) *Employees {
    e := new(Employees)
    e.name = n
    return e
}

func (e *Employees) Hello() string {
    return "名前：" + e.name
}

type Boss struct {
  Employees  // embeded
  age string  // Boss独自のフィールドを持たせるとする
}

func newBoss(n, a string) *Boss{
  b := new(Boss)
  b.name = n
  b.age = a
  
  return b
}

func (b *Boss) Hello() string {
    return b.name + b.age
}

func SignUp(p Person) string {
    return p.Hello()  + "で登録"
}

func main() {
    ps := []Person{
        newEmployees("従業員A"),
        newBoss("部長A ", "11"),
    }
    for _, p := range ps {
        fmt.Println(SignUp(p))
    }
}
```

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303093/069dbcf3-bfdf-e9ce-daf4-3908ae2af96d.png)


- ちょっと不細工ではありますが、無事それぞれのHelloメソッド（年齢を出す）を出力できました。

# 参考（むしろこっち読んだ方がわかりやすいです）
- [Go言語で「embedded で継承ができる」と思わないほうがいいのはなぜか？](https://qiita.com/Maki-Daisuke/items/511b8989e528f7c70f80)：めちゃめちゃ参考にしました。