接口(interface)概念
在 Go 语言中,接口(interface)是一个自定义类型,接口类型具体描述了一系列方法的集合。
接口又称为动态数据类型,在进行接口使用的的时候,会将接口对位置的动态类型改为所指向的类型,会将动态值改成所指向类型的结构体。
接口可以让我们将不同的类型绑定到一组公共的方法上,从而实现多态和灵活的设计。
接口类型是一种抽象的类型,它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合,它们只会展示出它们自己的方法。因此接口类型不能将其实例化。
Go通过接口实现了鸭子类型(duck-typing):“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
接口的定义
type Humaner interface{
SayHi()
}
- 接口命名习惯以 er 结尾
- 接口只有方法声明,没有实现,没有数据字段
- 接口可以匿名嵌入共它接口,或嵌入到结构中
接口的实现
- 接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是由用户定义的类型实现,一个实现了这些方法的具体类型是这个接口类型的实例。
- 如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的值存入接口类型的值。
- 在定义接口类型的变量以后,只要是实现了此接口方法的类型,就可以赋值给这个接口类型的变量。
- 赋给它什么类型就调用此类型实现的接口方法。
更为常用的方法是定义一个普通函数,函数的参数为接口类型,然后通过调用这个函数,实现不同的方法—相当于多态
- 也可以通过切片的方法实现
接口的继承
超集
如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集。
子集
对于两个集合A与B,如果集合A的任何一个元素都是集合B的元素,我们就说集合A包含于集合B,或集合B包含集合A,也说集合A是集合B的子集。如果集合A的任何一个元素都是集合B的元素,而集合B中至少有一个元素不属于集合A,则称集合A是集合B的真子集。空集是任何集合的子集。
任何一个集合是它本身的子集.空集是任何非空集合的真子集。
接口之间也是可以继承的
接口之间的转换—变量转换
超集可以转换为子集,反过来不可以
- 转换以后只能调用子集有的方法了
空接口
空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值。它有点类似于语言的void*类型。
当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中 Printxxx系列的所数,例如:
类型查询
我们知道 interface 的变量里面可以存储任意类型的数值(该类型实现了 interface)。那么我们怎么反向知道这个变量里面实际保存了的是哪个类型的对象呢?目前常用的有两种方法:
- comma-ok断言
- switch 测试
comma-ok断言
if value, ok := data.(int); ok == true{
}
switch测试
switch value := data.(type) {
case int:
.....
case string:
...........
case Student:
.........
}