[Go言語] コンストラクタの書き方

Go言語のコンストラクタは以下のように書くことが推奨されています。

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

package main

import "fmt"

type Person struct {
    Name string
    Age int
}

func NewPerson (name string, age int) *Person {
    if age < 0 {
        return nil
    }
    p := new(Person)
    p.Name = name
    p.Age = age
    return p
}

func main() {
    taro := NewPerson("Taro", 26)
    fmt.Printf("name: %s age: %d", taro.Name, taro.Age)
}

NewPersonは構造体の初期化を使って以下のように記述することもできます。

func NewPerson (name string, age int) *Person {
    if age < 0 {
        return nil
    }
    p := Person{name, age}
    return &p
}

Cに慣れた人にしてみるとローカル変数のポインタを返すことに違和感があるかもしれませんが、メモリ領域は呼ぶ度に新たに確保されます。

  • Effective Go – Constructors and composite literals
    http://golang.org/doc/effective_go.html#composite_literals

[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.

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

参考