0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?