Goでis-a関係を作る
Goには継承はなく、実装の再利用は構造体の埋め込みで行う。じっさいは委譲だが、見た目はオブジェクト指向言語で継承した場合のように使える。
package main type Super struct {} func (super Super) SuperMethod() {} type Sub struct {Super} func main() { sub := Sub{Super{}} sub.SuperMethod() // Subから直接Superのメソッドを実行できる }
ただしこれだと当然is-a関係にはならないため、以下のようにSuper
を要求する関数でSub
は使えない。
package main func RequiresSuper(super Super) Super { return super } type Super struct {} func (super Super) SuperMethod() {} type Sub struct {Super} func main() { sub := Sub{Super{}} sub.SuperMethod() super := RequiresSuper(sub) // コンパイルエラーになる super.SuperMethod() }
sub.Super
を渡すことで済む場合もあろうが、当然それはSuper
型の変数となってしまうので、今度はSub
のメソッドを実行できない。
package main func RequiresSuper(super Super) Super { return super } type Super struct {} func (super Super) SuperMethod() {} type Sub struct {Super} func main() { sub := Sub{Super{}} sub.SuperMethod() super := RequiresSuper(sub.Super) // ここを変更 super.SuperMethod() super.SubMethod() // コンパイルエラー }
どうするか。インターフェイスを使う。Super
がSuperInterface
を満たすようにし、Super
を直接でなく、SuperInterface
を要求するようにする。
package main func RequiresSuper(super SuperInterface) SuperInterface { return super } type SuperInterface interface { SuperMethod() } type Super struct {} func (super Super) SuperMethod() {} type Sub struct {Super} func (sub Sub) SubMethod() {} func main() { sub := Sub{Super{}} sub.SuperMethod() sub.SubMethod() super := RequiresSuper(sub) super.SuperMethod() super.(Sub).SubMethod() // とはいえ、SuperInterfaceはSubMethod()を当然持っていないので、ここではどうしても型表明が必要になる }
ここまで辿り着くのにかなりかかった。