一、接口的定义
接口是一个或者多个方法签名的集合,任何类型只要拥有与这对应的全部方法,就表示它实现
了该接口。
- 接⼝命名习惯以
er
结尾,结构体。- 接⼝只有方法签名,没有实现。
- 接⼝没有数据字段。
- 可在接⼝中嵌⼊其他接
- 类型可实现多个接⼝。
二、空接口
空接⼝
interface{}
没有任何⽅法签名,也就意味着任何类型都实现了空接⼝。因此,空接口可以存放任何类型的数据。
三、接口的执行机制
接⼝对象由
接⼝表 (interface table) 指针
和数据指针
组成。
runtiem.h
struct Iface
{
Itab* tab;
void* data;
};
struct Itab
{
InterfaceType* inter;
Type* type;
void (*fun[])(void);
};
接口值是一个两个字长度的数据结构,第一个字包含一个指向内部表的指针。这个内部表叫作iTable
,包含了所存储的值的类型信息。iTable
包含了已存储的值的类型信息以及与这个值相关联的一组方法。第二个字是一个指向所存储值的指针。
实体值赋值后接口值的简图:
实体指针赋值后接口值的简图:
四、接口转换
1、类型断言
func test1(i interface{}) {
if v, ok := i.(int); ok {
fmt.Printf("type is int, value: %v", v)
}
}
2、switch做类型批量判断,不支持fallthrough
。
func test2(i interface{}) {
switch v := i.(type) {
case nil:
fmt.Println("this is nil")
case int:
fmt.Println("this is int: ", v)
case string:
fmt.Println("this is string: ", v)
case float32:
fmt.Println("this is float32: ", v)
default:
fmt.Println("unknow type")
}
}
3、超集接口对象可转换为子集接口,反之出错。
type Peopler interface {
Study()
Animal
}
type Animal interface {
Eating()
}
type Student struct {
Name string
}
func (s Student) Study() {
fmt.Println("I am study.")
}
func (s Student) Eating() {
fmt.Println("I am Eating.")
}
func test3() {
var p Peopler = Student{Name: "XiaoMing"}
var a Animal = p
a.Eating()
}
五、让函数实现接口
type Tester interface {
Do()
}
type FuncDo func()
func (self FuncDo) Do() { self() }
func test4() {
var f Tester = FuncDo(func() { fmt.Println("hello world!") })
f.Do()
}