在 Go 语言中,interface 和函数一样,都是“第一公民”。interface 可以用在任何使用变量的地方。可以作为结构体内的字段,可以作为函数的形参和返回值,可以作为其他 interface 定义的内嵌字段。
interface 在大型项目中常常用来解耦。在层与层之间用 interface 进行抽象和解耦。由于 Go interface 非侵入的设计,使得抽象出来的代码特别简洁,这也符合 Go 语言设计之初的哲学。
1. 分类
interface源码路径: https://github.com/golang/go/blob/master/src/runtime/runtime2.go
interface在使用的过程中,共有两种表现形式,一种为空接口(empty interface),另一种为非空接口(non-empty interface)。
两种interface类型分别用两种struct表示,空接口为eface数据结构,非空接口为iface数据结构
1.1 空接口 eface
空接口eface结构,由两个属性构成,一个是类型信息_type,另一个是数据信息,其数据结构声明如下:
1. _type类型
此属性是Go语言中所有类型的公共描述,Go语言绝大多数的数据结构可以抽象成_type属性,是所有类型的公共描述,type负责决定data应该如何解释和操作,type的结构代码如下:
2. data属性
表示指向具体的实例数据的指针,它是一个unsafe.Pointer类型,相当于C语言的一个万能指针void∗。
1.2 非空接口 iface
1 | type iface struct { |
- interfacetype包含了一些关于interface本身的信息,例如package path,包含了method。这里的interfacetype是定义interface的一种抽象表示。
- type表示具体化的类型,与eface的type类型相同。
- hash字段其实是对_type.hash的复制,它会在interface的实例化时,用于快速判断目标类型和接口中的类型是否一致。Go语言的interface的Duck-typing机制也依赖这个字段实现。
- fun字段其实是一个动态大小的数组,虽然声明时固定大小为1,但在使用时会直接通过fun指针获取其中的数据,并且不会检查数组的边界,所以该数组中保存的元素数量是不确定的。
1. 举例
1 | type People interface{ |
live( )返给上层的是一个People interface{}类型,也就是一个iface struct{}类型。stu为nil,只是iface中的data为nil而已,但是iface struct{}本身并不为nil
2. Type Assertion 断言
我们知道使用 interface 断言的时候需要注意,不然很容易引入 panic。
2.1 断言
1 | func do(v interface{}) { |
这个过程体现在下面的几个函数上。
1 | // The assertXXX functions may fail (either panicking or returning false, |
3. 头脑风暴
- interface 分为两种,空接口 eface 和 非空接口 iface。
- 参数interface之所以不等于nil,是因为内部的data指向了nil,但是data不等于nil。
- 两个底层实现都有一个
_type
结构,进行断言。