多态行为
Go语言里定义的方法集的规则是:
从值的角度来看规则
Values | Methods Receivers |
---|---|
T | (t T) |
*T | (t T) and (t *T) |
T类型的值的方法集只包含值接收者声明的方法。而指向T类型的指针的方法集既包含值接收者声明的方法,也包含指针接收者声明的方法。
从接收者的角度来看规则
Values | Methods Receivers |
---|---|
(t T) | T and *T |
(t *T) | *T |
即:使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够调用对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够调用对应的接口。
package main
import (
"fmt"
)
type notifier interface {
notify()
}
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Println("send user email to ", u.name, u.email)
}
type admin struct {
name string
email string
}
func (a *admin) notify() {
fmt.Println("send user email to ", a.name, a.email)
}
func sendNotification(n notifier) {
n.notify()
}
func main() {
u := user{"bill", "qq.com"}
a := admin{"lisa", "sina.com"}
//sendNotification(u) // 此操作将编译不通过,不满足方法集规则
sendNotification(&u)
sendNotification(&a)
}
内嵌类型
package main
import (
"fmt"
)
type notifier interface {
notify()
}
type user struct {
name string
email string
}
func (u *user) notify() {
fmt.Println("send user email to ", u.name, u.email)
}
type admin struct {
/*
这里admin并不是一个user,而是包含关系。
从实现的角度上,内嵌字段会指导编译器生成额外的包装方法来委托已经声明好的方法,与下面形式是等价的
func (a admin) notify(){
}
*/
user // 匿名声明,将user 提升为admin的内部类型,包含其方法和属性
}
func (a *admin) notify() {
fmt.Println("send super email to ", a.name, a.email)
}
func sendNotification(n notifier) {
n.notify()
}
func main() {
//u := user{"bill", "qq.com"}
a := admin{
user{"lisa", "sina.com"},
}
//sendNotification(&u)
sendNotification(&a)
a.notify() // 若admin没有实现notify 则调用提升后的内部类方法,否则调用自己的方法
a.user.notify() // 调用内部类方法
}