go定义接口以及类怎么使用接口
多态是指代码可以根据类型的具体实现采取不同行为的能力。如果一个类型实现了某个接口,所有使用这个接口的地方,都可以支持这种类型的值。
- 接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型的值。对接口值方法的调用会执行接口值里存储的用户定义的类型的值对应的方法。因为任何用户定义的类型都可以实现任何接口,所以对接口值方法的调用自然就是一种多态。
下面将创建一个用户定义结构体并实现一个发送接口:
package main import "fmt" // 定义一个notifier接口 // 通知类行为的一个接口 type notifier interface { notify() } // 定义一个用户类 type user struct { name string email string } // nofity是使用指针接收者实现的方法 func (u *user) notify() { fmt.Print("发送一条邮件给%s<%s>", u.name, u.email) } func main() { // 创建一个用户并复制 user := user{"小明", "1001**@qq.com"} sendNotification(&user) } func sendNotification(n notifier) { n.notify() }
注意:这里传递给sendNotification方法的用户定义结构体值user,是使用引用的方式传递的。因为类在实现接口的时候传递的参数是引用类型:(u *user),如果你是使用值传递的话,编辑器会报错。
./demo.go:25:18: cannot use user (type user) as type notifier in argument to sendNotification: user does not implement notifier (notify method has pointer receiver)
进一步探索新问题,为什么上述使用值不行,使用引用可以呢?
如果你把是实现接口的传递参数改成值的形式而不是引用,你将会发现有所不同
// nofity是使用指针接收者实现的方法 func (u user) notify() { fmt.Print("发送一条邮件给%s<%s>", u.name, u.email) }
// 创建一个用户并复制
user := user{"小明", "1001**@qq.com"}
sendNotification(user)
sendNotification(&user)
你将会发现,使用引用的方式调用跟使用值的方式调用,编译器都不会报错,这是为什么?
- 因为底层实现是如果使用指针来实现一个接口(u *user),那么只有指向那个类型(user)的指针才能实现对应的接口。
- 如果使用值来实现一个接口,那么那个类型(user)的值和指针都能够实现对应的接口。
注意:使用指针实现接口和使用值实现接口有个区别在于,指针是指向内存同一块地址的,所以通过指针传递的参数,在函数体内执行结构体的改变会影响函数外的用户类型值,而使用值传递则不会 ,这也是在使用指针和使用值的不同场景选择的一个区别其中之一。
使用值:
package main import "fmt" // 定义一个notifier接口 // 通知类行为的一个接口 type notifier interface { notify() } // 定义一个用户类 type user struct { name string email string } // nofity是使用指针接收者实现的方法 func (u user) notify() { u.name = "小红" fmt.Print("发送一条邮件给%s<%s>", u.name, u.email) } func main() { // 创建一个用户并复制 user := user{"小明", "1001**@qq.com"} //sendNotification(user) sendNotification(&user) // 小明 fmt.Println(user.name) sendNotification(user) // 小明 fmt.Println(user.name) } func sendNotification(n notifier) { n.notify() }
使用指针:
package main import "fmt" // 定义一个notifier接口 // 通知类行为的一个接口 type notifier interface { notify() } // 定义一个用户类 type user struct { name string email string } // nofity是使用指针接收者实现的方法 func (u *user) notify() { u.name = "小红" fmt.Print("发送一条邮件给%s<%s>", u.name, u.email) } func main() { // 创建一个用户并复制 user := user{"小明", "1001**@qq.com"} //sendNotification(user) sendNotification(&user) // 小红 fmt.Println(user.name) } func sendNotification(n notifier) { n.notify() }