3

图片.png

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和变量的地址就会被赋值,具体如下图所示。
图片.png
从上图可以看出,在接口变量的内部,传入变量的类型信息,方法集和变量的地址被存储在一个结构体中,当调用接口提供的方法时,接口就会在它保存的实体类型里去找对应方法的实现,然后调用其来完成相应操作。

参考文献

  1. William Kennedy等《Go语言实战》第5章相关内容

这期的内容比较简短,但比较重要啊 ~~~

我是lioney,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题!


lioney
133 声望14 粉丝