LoginSignup
4
2

More than 5 years have passed since last update.

Goでinterfaceを戻り値としたメソッドチェーンすると死亡フラグなので避けたほうがよさそう

Posted at

相変わらずオブジェクト指向に汚染された脳味噌で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()

結果は、

ペタペタ
グワッグワッ!

odoroki256.png

ワンちゃんがアヒルになったよ!

どういうことかというと、Walk()はDogでは実装していないので、Duckのそれが呼ばれます。そしてDuckのselfがIDuckとして戻り値で返されるので、メソッドチェーン先のBurk()はDuckのものが呼ばれるのです。

Goでメソッドチェーン危険。

4
2
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
4
2