Go言語(プログラミング)入門メモ⑬

## Goにおけるインターフェース
Goのインターフェイスは、メソッドの名前のみを宣言したもので、そのメソッドを持つ型はインターフェースを実装していると判断される。
具体的に見るために、まずはHumanというインターフェースを作成し、{}の中に「Say()」とメソッドを書く。インターフェースでは、メソッド名のみを宣言し、処理のコードは書かない。
~~~
type Human interface {
    Say()
}
~~~
続いて、構造体を作成してインターフェースに当てはめる。string型のNameというフィールドを持つPersonという構造体を作成し、Personに紐づくメソッドとしてSayを作成する。
~~~
type Person struct {
    Name string
}

func (p Person) Say() {
    fmt.Println(p.Name)
}
~~~
Human型(インターフェース型)の変数mikeを宣言し、構造体Personに{"Mike"}を渡して代入する。「mike.Say()」と実行するとMikeと表示される。
~~~
func main() {
    var mike Human =  Person{"Mike"}
    mike.Say()
}

//以下のように表示される
Mike
~~~
Human型の変数にPersonという構造体を代入する場合、PersonはSayというメソッドを持っている必要がある。
Sayメソッドをコメントアウトするなどして実装しない状況を作ると、エラーになる。
このように指定したメソッドを必ず持たせたいときに、インターフェースを使う。

## インターフェースのメソッドで構造体の中身を書き換える場合
Sayメソッドの処理を追加する。p.Nameに「Mr.」を加える。構造体の中身を書き換えることになるのでPersonの前に＊を付けてポインタレシーバにする必要がある。
ただし、Sayメソッドを変更しただけだとエラーになる。
~~~
func (p *Person) Say() {
    p.Name = "Mr." + p.Name
    fmt.Println(p.Name)
}

//
エラーとなる
~~~

Stayメソッドはポインタレシーバとなるので、main関数からSayメソッドを呼び出す際に、アドレスとして渡す必要がある。
~~~
func (p *Person) Say() {
    p.Name = "Mr." + p.Name
    fmt.Println(p.Name)
}

func main() {
    var mike Human = &Person{"Mike"}    //アドレスを渡す
    mike.Say()
}

//以下のように出力される
Mr.Mike
~~~

## ダックタイピング
Humanというインターフェースを、引数として受け付ける関数DriveCarを作る。引数humanのSayメソッドの返り値が「Mr.Mike」であれば「Run」、そうでなければ「Get Out」を表示する。
また、Sayメソッドは、変え入地をstring型の文字列と比較したいのでp.Nameをstring型で返すようにする。Humanインターフェース内のSayも返り値をstring型にする。

~~~
type Human interface {
    Say() string           //string型にする
}
type Person struct {
    Name string
}

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

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

//以下のように出力される
Mr.Mike
Run
~~~
Nameを「X」として作成したPersonを変数xに代入し、DriveCarメソッドの引数に指定して実行すると、DriveCarメソッドのif文の処理で「Get Out」が表示される。
~~~
func main() {
    var mike Human = &Person{"Mike"}
    var x Human = &Person{"X"}
    DriveCar(mike)
    DriveCar(x)
}

//以下のように出力される
Mr.Mike
Run
Mr.X
Get Out
~~~
構造体PersonはHumanインターフェースうぃ明示的に実装していないがHumanインターフェースのメソッドをすべて実装しているので、Humanインターフェースを実装したことになる。そのため、構造体PersonをHumanインターフェースに代入できる。

※ダックタイピングは、「もしもアヒルのように歩き、アヒルのように鳴くならそれはアヒルであろう」という考え方が由来。つまり、構造体Personは「Humanインターフェースのメソッドをすべて実装しているなら、それはHumanインターフェースを実装したものだろう」という考え方になる。

## インターフェースを実装していない場合
DriveCarは引数にHumanインターフェースを指定しているので、Sayメソッドがない構造体は引数に使えない。たとえば、string型のNameフィールドを持つDogという構造体を作る。このDogはSayメソッドを持たないため、DriveCarの引数に指定してもエラーになる。

~~~
type Dog struct {
    Name string
}
中略
func main() {
    var mike Human = &Person{"Mike"}
    var x Human = &Person{"X"}
    var dog Dog = Dog{"dog"}
    DriveCar(mike)
    DriveCar(x)
    DriveCar(dog)
}

//
エラーとなる
~~~

## 学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP

・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897