【Go】学習メモ1:インターフェースとダックタイピング
アプリケーションを作りたくてGo言語を学んでいます。
所々躓いた点は自分なりに理解した(と思われる)内容やイメージを残していきたいと思います。
如何せん初心者なもので、もし理解が誤っていたら教えていただけると幸いです・・・!
インターフェースのイメージ
インターフェースは次のようなイメージを持ってます。
上から、人類→個人→メソッドといったイメージです。
【インターフェース】
Humanは「喋る」、「歩く」、「寝る」などのメソッドを持っています。(ここではまだ「喋る」や「歩く」がどのような動作なのかは分からない)
【ストラクト】
Personは構造体を表します。(ここでは個人の宣言と名前や年齢などの属性を用意しています。歩くや寝るの動作もあるので、ストレス状況や筋力などの属性も用意してもいいと思います!)
【メソッド】
先ほどの通りHumanに属するPersonはインターフェースにて宣言した「喋る」や「歩く」が出来ます。ここでは『喋るとは?歩くとは?』どのような動作を意味するのかを記述します。
つまり、
①予めインターフェース内にて人型が可能な動作を宣言しておき、
②人型に属する個人が ③インターフェース内で定義した動作をメソッドとして用意する。
そうすることで、人型に割り当てた個人は、いつでもインターフェース内で割り当てた動作を呼び出すことが可能となる。
そんな便利さを持ち合わせているのがインターフェース。でいいのでしょうか(汗
先ほどの図を別の観点からイメージすると下のようになります。
このように、Person(struct)をHuman(Interface)に代入することで、HumanであるPersonはPreson.Say()が実行可能となります。
ある個人は"人型"であり、"人型"は喋るので、ある個人は"喋れる"ということです。
またHuman(Interface)にSleep()などほかのメソッドも宣言したら同様にPersonで使える関数として定義しなければなりません。
実装
これから上のイメージの通り実装していきます。
①予めインターフェース内にて人型が可能な動作(今回はSay()のみ)を宣言しておき、
②人型に属する個人(属性は名前のみ)が ③行えるインターフェース内で定義した動作をメソッドとして用意する。
の順番で進めます。
①予めインターフェース内にて人型が可能な動作(今回はSay()のみ)を宣言しておき、
package main import "fmt" type Human interface { Say() }
②人型に属する個人(属性は名前のみ)が
type Person struct { Name string }
③行えるインターフェース内で定義した動作をメソッドとして用意する。
func (p Person) Say() {
fmt.Println(p.Name)
}
あとはmain関数内で、Humanにmikeという名前のPersonを代入してsayを実行する。
func main() { var mike Human = Person{"mike"} mike.Say() //"mike" }
ダックタイピング
"If it walks like a duck and quacks like a duck, it must be a duck"
(もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない)
ja.wikipedia.org
つまり、
"Person("mike")がインターフェースHumanで定義したSay()の関数を持ち合わせているのであれば、PersonもインターフェースHumanを満たしている"ということです。(恐らく・・・)
分かりにくいので例えば、mikeがレンタカーで車を予約し、"Mr.mike"なら乗車可能、それ以外なら乗車不可といったメッセージがアウトプットされるコメントを出力したいとします。
この場合、Person.Say()には戻り値を持たせたいので
①のインターフェースのメソッドSay()の戻り値を文字型に
type Human interface { Say() string }
③のSay()には戻り値を、頭に"Mr."をつけるため、Personの中身を変更するのでポインタレシーバー(*Person)に変更
func (p *Person) Say() string { p.Name = "Mr." + p.Name return p.Name }
新たにDriveCarという関数を定義。
func DriveCar(human Human) { if human.Say() == "Mr.mike" { fmt.Println("ok") } else { fmt.Println("get out!") } }
mikeという構造を持った人型(Human)のPerson(個人)がSay()のメソッドを持ち合わせているため、
DriveCar関数が実行することができました。
先ほどSay()をポインタレシーバとしたので、Person{"mike"}にも&をつけます。
func main() { var mike Human = &Person{"mike"} var x Human = &Person{"x"} DriveCar(mike) // "ok" DriveCar(x) // "get out!" }
今回は以上になります。