interface 是 Go 语言的基础特性之一,可以理解为一种类型的规范或者约定。
接口的声明
1 | // 空接口 |
接口指定了类型应该具有的方法,类型决定了如何实现这些方法。
1 | // 有方法列表的接口 |
接口的实现
Go语言中,接口的实现是隐式的。不用明确地指出某一个类型实现了某一个接口,只要在某一类型的方法中实现了接口中的全部方法签名,就意味着此类型实现了这一接口。
1 | type PeopleInface interface { |
接口动态类型
存储在接口变量中的类型称为接口的动态类型,而将接口本身的类型称为接口的静态类型
下面的代码中,sp是接口变量,sp的动态类型是student,静态类型是speak。sp的静态类型永远是speak,动态类型却会随着我们赋给它的动态值而变
1 | package main |
接口动态调用
当接口变量中存储了具体的动态类型时,可以调用接口中所有的方法。在对接口变量进行动态调用时,调用的方法只能是接口中具有的方法。
1 | type Speak interface { |
指针和接口
在实现接口的时候有两种方式,结构体实现和指针实现
《Go语言设计与实现》中的图

结构体类型和指针类型是不同的,在实现接口时这两种类型也不能划等号。虽然两种类型不同,但是上图中的两种实现不可以同时存在,Go 语言的编译器会在结构体类型和指针类型都实现一个方法时报错 “method redeclared”。
实现接口时可以选择接受者的类型,即结构体或者结构体指针,在初始化时也可以初始化成结构体或者指针。
在初始化成结构体的时候,是可以调用接受者是结构体和结构体指针的方法。
在初始化成指针的时候,只可以调用接受者是结构体指针的方法。
……这特么的看代码吧!
1 | type Duck interface { |
至于为什么这样,在《Go语言设计与实现》中有这样的解释

两种接口的数据结构
Go 语言根据接口类型是否包含一组方法将接口类型分成了两类:
- 使用
runtime.iface结构体表示包含方法的接口 - 使用
runtime.eface结构体表示不包含任何方法的interface{}类型
eface结构体
1 | type eface struct { // 16 字节 |
size字段存储了类型占用的内存空间,为内存空间的分配提供信息;hash字段能够帮助我们快速确定类型是否相等;equal字段用于判断当前类型的多个对象是否相等,该字段是为了减少 Go 语言二进制包大小从typeAlg结构体中迁移过来的
iface结构体
runtime.itab 结构体是接口类型的核心组成部分,每一个 runtime.itab 都占 32 字节,我们可以将其看成接口类型和具体类型的组合,它们分别用 inter 和 _type 两个字段表示:
1 | type itab struct { // 32 字节 |
hash是对_type.hash的拷贝,当我们想将interface类型转换成具体类型时,可以使用该字段快速判断目标类型和具体类型runtime._type是否一致fun是一个动态大小的数组,它是一个用于动态派发的虚函数表,存储了一组函数指针。虽然该变量被声明成大小固定的数组,但是在使用时会通过原始指针获取其中的数据,所以fun数组中保存的元素数量是不确定的