[Go言語] アノニマスフィールド(anonymous field)による継承とオーバーライド

Go言語には継承はありませんが、アノニマスフィールド(anonymous field)を使うことで共通のフィールドとメソッドを持つ構造体(struct)を作ることができます。詳しくはドキュメント等を参照して下さい。

今回は、アノニマスフィールドで継承した場合のオーバーライドの扱いを調べました。インターフェース渡しのメソッドでは元の構造体のメソッドが呼ばれます。ちょっと例が長いですが。

インターフェース渡しの例

http://play.golang.org/p/ebyaLR1ruQ

package main

import "fmt"

type Animal interface {
    Eat()
}

type Mammal struct {
    Weight int
}

type Human struct {
    Mammal
}

func (a *Mammal) Eat() {
    a.Weight += 11
}

func (h *Human) Eat() {
    h.Weight += 23
}

func main() {
    // Human
    h := &Human{Mammal{1}}

    serveFood(h)

    fmt.Printf("Human weight is %d\n", h.Weight)

    // Mammal
    m := &Mammal{1}

    serveFood(m)

    fmt.Printf("Mammal weight is %d\n", m.Weight)
}

func serveFood(a Animal) {
    a.Eat()
}

実行結果

Human weight is 24
Mammal weight is 12
Program exited.

一方、メソッドの引数にポインタを渡すとMammalのメソッドが呼ばれてしまいます。

ポインタ渡しの例

http://play.golang.org/p/ZEiHehkhID

package main

import "fmt"

type Mammal struct {
    Weight int
}

type Human struct {
    Mammal
}

func (a *Mammal) Eat() {
    a.Weight += 11
}

func (h *Human) Eat() {
    h.Weight += 23
}

func main() {
    // Human
    h := &Human{Mammal{1}}

    serveFood(&h.Mammal)

    fmt.Printf("Human weight is %d\n", h.Weight)
}

func serveFood(a *Mammal) {
    a.Eat()
}

実行結果

Human weight is 12
Program exited.

アノニマスフィールドのポインタを使うのは避けた方が良さそうです。

余談ですが、Goにはオーバーロードはありません。
http://golang.org/doc/faq#overloading

参考

[Go言語] インターフェース引数は値渡しなのか参照渡しなのか

Go言語(golang)にはポインタとインターフェースがありますが、「インターフェースへのポインタ」で渡す必要があるのかどうか。

結論から言うと、インターフェースはインスタンスへの参照を持っているのでインターフェースへのポインタを渡す必要はありません。
以下の例では、serveFoodメソッドにインターフェースで渡していますが、元のインスタンスが変更されていることが分かります。

http://play.golang.org/p/M6is2Gpe0B

package main

import "fmt"

type Animal interface {
    Eat()
}

type Human struct {
    Vital string
}

func (h *Human) Eat() {
    h.Vital = "full"
}

func main() {
    a := &Human{"empty"}

    serveFood(a)

    fmt.Printf("vital is %s", a.Vital)
}

func serveFood(a Animal) {
    a.Eat()
}

実行結果

vital is full
Program exited.

まあ、インターフェースの値って何なのか考えてみれば明らかだと思いますが、ポインタに不慣れな人には理解が難しいところかもしれません。

参考