1. 接口的功能
- 接口是用来定义行为的类型。这些被定义的行为不由接口实现,而是通过方法由用户定义的类型实现。
- 如果用户定义的类型实现了某个接口声明的全部方法,那么这个用户定义的类型的变量就可以赋给这个接口类型的变量。
- 用户定义的任何类型都可以实现接口,所以对接口类型变量的调用就可以形成多态调用。
2. 接口变量的内存布局
我们先看下面一个使用接口的小例子:
package main
import "fmt"
// 自定义接口
type notifier interface {
notify()
}
// 定义一个多态调用的函数
func sendNotification(n notifier) {
n.notify()
}
// 自定义类型
type user struct {
name string
email string
}
// 实现notifier接口的方法
func (u *user) notify() {
// 模拟发邮件的功能
fmt.Printf("Send email to %s.\n", u.name)
}
func main() {
u := user{
name: "lioney",
email: "lioney_liu@sina.com",
}
sendNotification(&u) // Send email to lioney.
}
接口变量是一个占有两个字长度的数据结构,第一个字包含一个指向内部表的指针,叫iTable,iTable包含了所存储变量的类型信息以及和这个变量相关的方法集。第二个字是一个指向所存储变量的指针。当上述代码执行sendNotification(&u),iTable和变量的地址就会被赋值,具体如下图所示。
从上图可以看出,在接口变量的内部,传入变量的类型信息,方法集和变量的地址被存储在一个结构体中,当调用接口提供的方法时,接口就会在它保存的实体类型里去找对应方法的实现,然后调用其来完成相应操作。
参考文献
- William Kennedy等《Go语言实战》第5章相关内容
这期的内容比较简短,但比较重要啊 ~~~
我是lioney,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题!
有疑问加站长微信联系(非本文作者)