type notifier interface {
notify()
}
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Printf("sending %v %v", u.email, u.name)
}
func sendNotification(n notifier) {
n.notify()
}
func main() {
u := user{name: "name", email: "email"}
sendNotification(&u)
}
代码中user实现了接口notify,但是编译执行时报错
cannot use u (type user) as type notifier in argument to sendNotification:
user does not implement notifier (notify method has pointer receiver)
为什么会这样呢?让我们看一下golang规范中的描述:
Values | Methods Receivers |
---|---|
T | (t T) |
*T | (t T) and (t *T) |
表格的意思是,如果给interface传入的是值,那么只能调用Receiver是值的Methods,如果给interface传入的是指针,那么能调用Receiver是值的Methods或指针的Methods.
表格反过来表示
Methods Receivers | Values |
---|---|
*T | (t *T) |
T | (t T) and (t *T) |
如果Receiver是指针,传递给interface的参数只能是指针,如果Receiver是指,那么传递给interface的参数可以是指针或指。
之所以有这样的限制在于并非所有的指都是可以取地址的。
type duration int
func (d *duration) pretty() string {
return fmt.Sprintf("durantion:%d", *d)
}
func main() {
duration(23).pretty()
}
程序会报错:
.\main.go:60: cannot call pointer method on duration(23)
.\main.go:60: cannot take the address of duration(23)
duration(23)是无法取地址的。
golang允许使用已有的类型并扩展或改变已有类型的行为,通过Type embedding实现。Type embedding通过在struct 中嵌入已有类型实现。新的类型拥有被嵌入类型的所有成员和方法,而且可以在struct中扩展或改变被嵌入类型的方法。
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Printf("sending %v %v\n", u.email, u.name)
}
type admin struct {
user
lever string
}
func main() {
ad := admin{
user: user{
name: "jonh",
email: "sss@ss",
},
lever: "super",
}
ad.user.notify()
ad.notify()
}
结果
sending sss@ss jonh
sending sss@ss jonh
可以看到admin虽然没定义方法notify(),但是拥有了user的notify()方法。
加上interface
type notifier interface {
notify()
}
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Printf("sending %v %v\n", u.email, u.name)
}
type admin struct {
user
lever string
}
func sendNotification(n notifier) {
n.notify()
}
func main() {
ad := admin{
user: user{
name: "jonh",
email: "sss@ss",
},
lever: "super",
}
ad.user.notify()
ad.notify()
sendNotification(&ad)
}
结果
sending sss@ss jonh
sending sss@ss jonh
sending sss@ss jonh
如果admin要更改notify的话:
添加
func (u *admin) notify() {
fmt.Printf("admin sending %v %v\n", u.email, u.name)
}
结果:
sending sss@ss jonh
admin sending sss@ss jonh
admin sending sss@ss jonh
可以看到notify已经更改,不过可以通过ad.user.notify()访问内部类型的方法。
我们还可以将类型的指针作为嵌入类型。
type padmin struct {
*user
}
func main() {
ad := padmin{
user: &user{
name: "wdy",
email: "000",
},
}
ad.user.notify()
ad.notify()
sendNotification(&ad)
sendNotification(ad)
}
运行后结果:
sending 000 wdy
sending 000 wdy
sending 000 wdy
sending 000 wdy
此时我们注意到,可以给函数sendNotification直接传入ad或&ad。
sendNotification(&ad)
sendNotification(ad)