DRYな備忘録

Don't Repeat Yourself.

Go言語でinterfaceをimpleしてるつもりが「does not implement (method has pointer receiver)」って叱られる【golang】【pointer】【ダックタイピング】

問題

Go言語はinterfaceによる型の制約ができる。逆にinterfaceで宣言したメソッドをすべて満たすいかなるstructもそのinterfaceを満たすものとして扱える。いわゆるダックタイピング。

参考

で、interfaceを満たすstructを定義したつもりが「インターフェース実装できてないよ!そのメソッドポインターを取らなきゃ!」と叱られる。

原文(これはうごかない)

package main

type Greeter interface {
    Greet()
}
type Person struct {
    name string
}
func (p *Person) Greet() {
    println("Hi! I'm ", p.name)
}
func GetGreeterByName(name string) Greeter {
    return Person{name}
}
func main() {
    p := GetGreeterByName("otiai10")
    p.Greet()
}

prog.go:13: cannot use Person literal (type Person) as type Greeter in return argument: Person does not implement Greeter (Greet method has pointer receiver) [process exited with non-zero status]

ふぇぇ

調査

このスレッドが一番わかりやすい

解決

package main

type Greeter interface {
    Greet()
    ChangeNameTo(new string)
}
type Person struct {
    name string
}
func (p *Person) Greet() {
    println("Hi! I'm ", p.name)
}
func (p *Person) ChangeNameTo(new string) {
    p.name = new
}
func GetGreeterByName(name string) Greeter {
    // ここで参照を返す
    return &Person{name}
}
func main() {
    p := GetGreeterByName("otiai10")
    p.Greet()
    p.ChangeNameTo("otiai12")
    p.Greet()
}
// Hi! I'm  otiai10
// Hi! I'm  otiai12

つまり

interfaceの定義は、その型がバリューだろうとポインタだろうと、どっちでも定義可能で、しかしながらメソッドのなかでポインタで扱うんだったらお前それポインタなんだよな?な?ということ。 (p Person)を取るメソッドだけの定義だったら返すPerson&Person{}ではなくPerson{}でいい。

そんかし、そん時はもちろんポインタじゃないのでメソッド内で自身を上書きできない。↓

package main

type Greeter interface {
    Greet()
    ChangeNameTo(new string)
}
type Person struct {
    name string
}
func (p Person) Greet() {
    println("Hi! I'm ", p.name)
}
func (p Person) ChangeNameTo(new string) {
    p.name = new
}
func GetGreeterByName(name string) Greeter {
    return Person{name}
}
func main() {
    p := GetGreeterByName("otiai10")
    p.Greet()
    p.ChangeNameTo("otiai12")
    p.Greet()
}
// Hi! I'm  otiai10
// Hi! I'm  otiai10

雑感

f:id:otiai10:20140527223948p:plain

これが雑感です。

DRYな備忘録