先来看一段代码
package main
import (
"fmt"
)
type notifier interface {
notify()
}
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
func main() {
u := user{"Bill", "bill@email.com"}
sendNotification(u)
}
func sendNotification(n notifier) {
n.notify()
}
这个例子来自《Go语言实战》的第五章lisitening36。运行这个例子,不出所料的话,会报错,详情如下:
./listing36.go:33:18: cannot use u (type user) as type notifier in argument to sendNotification:
user does not implement notifier (notify method has pointer receiver)
先说明一下,sendNotification方法能够接受一个实现类(比如user)来调用notifier接口中notify(),这是毋庸置疑的。
错误提示的意思就是:编译器告诉我们 user类型的值并没有实现这个接口。问题是我们明明已经实现了,编译器却不让我们通过,这是为什么。其实错误信息也已经明确告诉我们了:notify method has pointer receiver。notify方法接收者是指针,但是我们调用的时候sendNotification(u),是通过值调用,所以报错了。
规范里描述的方法集
Values Methods Receivers
--------------------------------
T (t T)
*T (t T) and (t *T)
描述中说到,T 类型的值的方法集只包含值接收者声明的方法,而指向 T 类型的指针的方法集既包含值接收者声明的方法,也包含指针接收 者声明的方法
另一个角度看方法集
Receivers Values Methods
--------------------------------
(t T) T and *T
(t *T) *T
从这里可以看到,如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口。
看回原来代码
u := user{"Bill", "bill@email.com"}
sendNotification(u)
这下知道是什么问题了吧?我们把u(实现类)的值作为参数传入sendNotification方法中,这是不允许的。因为实现notify() 方法时,是以指针的形式作为接收者(func (u *user) notify() ),所以这里应该改为sendNotification(&u)。或者将func (u user) notify() 的user 改为 user。问题即可以解决。