はじめに
ダックタイピングは、巷ではよく「もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである」
と表現されます。どういうことなのでしょうか。
Go言語で簡単なソースをコーディングしてみました。コメントベースで追っていきましょう。
ソース
package main
import "fmt"
// Fish interfaceは Swimメソッドを持つ。
type Fish interface {
Swim() string
}
// Bird interfaceは Flyメソッドを持つ。
type Bird interface {
Fly() string
}
// アヒルは泳げるし、少し飛べる。
// それらを踏まえて Duck ストラクトを定義する。
type Duck struct {
duckSwim string
duckFly string
}
// Duck ストラクトにSwimメソッドを持たせる。
func (d *Duck) Swim() string {
return d.duckSwim
}
// Duck ストラクトにFlyメソッドを持たせる。
func (d *Duck) Fly() string {
return d.duckFly
}
// このFishSwim関数は Fish interface以外の引数は取らない
func FishSwim(f Fish) string {
return f.Swim()
}
// このBirdFly関数は Bird interface 以外の引数は取らない
func BirdFly(b Bird) string {
return b.Fly()
}
func main() {
// 先程定義したストラクト Duckに文字列をセット
dc := &Duck{
"私は泳げます。",
"私は飛べます。",
}
// アヒルなので、泳げる。
fmt.Println(dc.Swim())
// アヒルなので、飛べる。
fmt.Println(dc.Fly())
// FishSwim関数の引数はFishのみのはずだが、Duckを渡すと泳げると言う。
fmt.Println(
"SaySwim :",
FishSwim(dc),
)
// BirdFly関数の引数はBirdのみのはずだが、Duckを渡すと飛べると言う。
fmt.Println(
"SayFry :",
BirdFly(dc),
)
}
まとめ
引数にFishしか受け取らないはずのFishSwim関数と
引数にBirdしか受け取らないはずのBirdFly関数が
Duckストラクトを受け取って「飛べる」とか「泳げる」とか言えるようになりました。
インターフェイス型のFish,Birdが必要なメソッドを持っていたからですね。
オブジェクトの振る舞いが問題なければ、
それを必要な引数として取り扱える事が
ダックタイピングの概要でしょうか。