在 Go 语言中,interface 和函数一样,都是“第一公民”。interface 可以用在任何使用变量的地方。可以作为结构体内的字段,可以作为函数的形参和返回值,可以作为其他 interface 定义的内嵌字段。
interface 在大型项目中常常用来解耦。在层与层之间用 interface 进行抽象和解耦。由于 Go interface 非侵入的设计,使得抽象出来的代码特别简洁,这也符合 Go 语言设计之初的哲学。
1. interface
interface源码路径: https://github.com/golang/go/blob/master/src/runtime/runtime2.go
1.1 非空接口 iface
1 | type iface struct { |
- 包含两个数据,一个指针指向真正的结构体地址,一个itab 记录了接口类型信息和实现的方法。
- fun字段其实是一个动态大小的数组,虽然声明时固定大小为1。使用时会直接通过fun指针获取其中的数据,该数组中保存的元素数量是不确定的。
示例说明:
1 | type People interface{ |
live( )返给上层的是一个People interface{}类型,也就是一个iface struct{}类型。stu为nil,只是iface中的data为nil而已,但是iface struct{}本身并不为nil

1.2 空接口 eface
空接口eface结构,由两个属性构成,一个是类型信息_type,另一个是数据信息。空接口不需要有方法,所以数据结构更简约。

data属性
:表示指向具体的实例数据的指针,它是一个unsafe.Pointer类型,相当于C语言的一个万能指针void∗。
_type类型
: 此属性是Go语言中所有类型的公共描述,Go语言绝大多数的数据结构可以抽象成_type属性,是所有类型的公共描述,type负责决定data应该如何解释和操作,type的结构代码如下:

函数调用的时候,会先转成eface再传参,所以判断nil永远不会为true。虽然内部的data指向了nil,但是data不等于nil。
2. 类型断言
2.1 相同内部函数可以转换
1 | package main |
2.2 断言
1 | func do(v interface{}) { |
这个过程体现在下面的几个函数上。
1 | // The assertXXX functions may fail (either panicking or returning false, |
3. 头脑风暴
3.1 自动结构体指针方法
如果struct 实现了一个方法,编译的时候,再会偷偷的多实现一个指针struct的方法。
用指针实现了方法,不会增加一个新的。
1 | type A struct { |
3.2 nil 空接口 空结构体
- nil 是空,是6种类型的零值(pointer,channel,fuc,interface,map,slice)。
- nil 不等于 nil。
- nil 不等于 空 struct。
- 空 interface没赋值时等于 nil。赋值为nil了,这时候就不等于nil了(因为有了类型信息)。
3.3 总结
- interface 分为两种,空接口 eface 和 非空接口 iface。
- 参数interface之所以不等于nil,是因为内部的data指向了nil,但是data不等于nil。
- 两个底层实现都有一个
_type
结构,进行断言。