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