相変わらずオブジェクト指向に汚染された脳味噌でGoで書いてると、意図しないstructの関数が呼び出されて死ぬ事態に何度も遭遇します・・・今回はメソッドチェーンで死にました。
type IDuck interface {
Walk() IDuck
Bark() IDuck
}
このようにメソッドチェーンで使うことを想定。
duck.Walk().Bark()
Walk、Bark関数を実装したDuckを作る。つまりIDockにもなれる。
type Duck struct {
}
func (self *Duck) Walk() IDuck {
fmt.Println("ペタペタ")
return self
}
func (self *Duck) Burk() IDuck {
fmt.Println("グワッグワッ!")
return self
}
Duckを拡張したDogを作り、Burkだけ書き換える。
type Dog struct {
Duck
}
func (self *Dog) Burk() IDuck {
fmt.Println("わんわん!")
return self
}
DogをIDuckに渡してinterfaceでメソッドチェーンしてみる。
dog := &Dog{}
var iduck IDuck = dog
iduck.Burk().Walk()
結果はもちろん
わんわん!
ペタペタ
これとは逆にWalk -> Burkでメソッドチェーンする。
dog := &Dog{}
var iduck IDuck = dog
iduck.Walk().Burk()
結果は、
ペタペタ
グワッグワッ!
ワンちゃんがアヒルになったよ!
どういうことかというと、Walk()はDogでは実装していないので、Duckのそれが呼ばれます。そしてDuckのselfがIDuckとして戻り値で返されるので、メソッドチェーン先のBurk()はDuckのものが呼ばれるのです。
Goでメソッドチェーン危険。