interfaceを受け取る関数に構造体を渡そうとしたところ、エラーが出てきてちょっとつまづいたのでメモです。
hello world
を出力するシンプルなプログラムを見ながら挙動を確認します。
うまくいかない場合
以下のコードだと Type does not implement 'sampleInterface' as the ... has a pointer receiver
というエラーが出てうまくいきません。
main.go
package main
import "fmt"
type sampleInterface interface {
DoSomething()
}
func interfaceReceiverFunc(si sampleInterface) {
si.DoSomething()
}
type sampleStruct struct {}
func (s *sampleStruct) DoSomething() {
fmt.Println("hello world")
}
func main() {
s := sampleStruct{}
interfaceReceiverFunc(s)
}
うまくいく場合その1:構造体のポインタを渡す
mainの中身をポインタに直せばうまくいきます。
main.go
func main() {
s := &sampleStruct{}
interfaceReceiverFunc(s)
}
なぜでこれでうまくいくのか?以下のコードを見るとポインタレシーバに対して、インターフェースのメソッドが定義されているためです。DoSomething
は*sampleStruct
のメソッドであり、sampleStruct
のメソッドではありません。なのでポインタで渡すことでうまくいったのです。
func (s *sampleStruct) DoSomething() {
fmt.Println("hello world")
}
うまくいく場合その2:構造体レシーバを実体にする
構造体のレシーバを実体にすれば、回避できます。ただこれよりはポインタレシーバにする場合がほとんどだと思うので、その1がいいかと思います。
main.go
func (s sampleStruct) DoSomething() {
fmt.Println("hello world")
}
func main() {
s := sampleStruct{}
interfaceReceiverFunc(s)
}
参考
以下が参考になりました。
こちらに以下のように書かれていまして、そちらをほぼ意訳した感じになります。
- A pointer to the value must be used, whose method set will include the method with the pointer receiver
- Or the receiver type must be changed to non-pointer, so the method set of the non-pointer concrete type will also contain the method (and thus satisfy the interface). This may or may not be viable, as if the method has to modify the value, a non-pointer receiver is not an option.