1.Go语言的接口是一些方法的集合,只要一个数据类型附带的方法集合是某一个接口的方法集合的超级,那么就可以判断该数据类型实现了这个接口。
2.接口声明时要以关键字type作为开始,除此之外,接口类型声明还包含了接口类型的名称、关键字interface和由花括号{}括起来的方法声明的集合。下面是一个简单的声明一个A接口示例:
type A interface{ Update() int Delete(i,j int) bool Add(i,j int) }
3.一个接口类型可以嵌入到另外一个接口类型中,可以认为是接口聚合,下面声明一个B接口,这个接口集合了A接口。
type B interface{ A Remove() }
上面声明了一个B接口类型,B接口实际上包含了4个方法,分别是Update,Delete,Add,以及Remove,前面的3个方法声明其实都是被包含在接口类型A中的,也就是说在接口声明中嵌入另一个接口类型声明的作用—将一个接口的方法集合中的方法批量地添加到另一个接口的方法集合中。java语言通过接口继承来实现接口方法的融合,Go语言可以说B接口继承了A接口。接口类型的嵌入有一个约束,那就是不能嵌入自身,这其中就包括的直接嵌入和间接嵌入,实例如下:
type X interface{ X }
//上面这个示例是接口的自我包含,这个是不允许的
type Y interface{ Z }
type Z interface{ Y }
3.interface可以被任意类型实现,一个对象也可以实现任意多个interface,任意的类型都实现了空interface.
//定义接口类型AI
type AI interface {
Add(key string)
Update(key string)
Remove(key string)
}
//定义接口类型BI
type BI interface {
Add(key string)
Update(key string)
Drop(key string)
}
//定义接口类型CI
type CI interface {
Add(key string)
Update(key string)
Compare(key string)
}
//下面三个方法分别实现了AI接口的三个方法,结构体A实现了AI的所用方法
func (h *A)Add(key string){
fmt.Printf("A Struct Add key ",key)
}
func (h *A) Update(key string) {
fmt.Printf("A Struct Add key ",key)
}
func (h *A) Remove(key string) {
fmt.Printf("A Struct Remove key ",key)
}
//结构体C聚合结构体A的数据类型,结构体A实现了AI的接口,那么下面这个方法代表结构体C重载了A的SayHi方法
func (e *C)Add(key string) {
fmt.Printf("C Struct Override A Struct Add method key ",key)
}
//结构体B实现了接口类型BI的Drop方法,由于B结构体聚会了A结构体,这样B结构继承了A结构实现的其他方法
func (s *B) Drop(key string) {
fmt.Printf("C Struct Drop method ",key)
}
//结构体C实现了接口类型CI的Compare方法,这样C结构继承了A结构实现的其他方法
func (e *C) Compare(key string) {
fmt.Printf("C Struct Compare method ",key)
}
//结构体声明
type A struct {
name string
age int
phone string
}
type B struct {
A
school string
loan float32
}
type C struct {
A
company string
money float32
}
4.interface值
1.如果我们定义了一个interface变量,那么这个变量里面可以存实现这个interface的任意类型的对象,上面的例子中,如果我们定义一个AI interface类型的变量ai,那么这个ai可以存放A,B,C的值,以为这些结构体实现了ai的方法集合。
5.空interface
空interface{}不包含任何的method,所有的类型都实现了空interface。空interface对于描述起不到任何的作用,空interface可以存储任意类型的数值。它有点类似于C语言的void*类型。
// 定义a为空接口
var a interface{}
var i int = 5
s := "Hello world"
// a可以存储任意类型的数值
a = i //把int类型的变量赋值给interface对象a
a = s //把字符串类型的变量赋值给interface对象a
6.interface函数参数
interface的变量可以持有任意实现该interface类型的对象,这给我们编写函数(包括method)提供了一些额外的思考,我们可以通过定义interface参数,让函数接受各种类型的参数。
func add(i interface,j interface) interface{ }
7.interface变量存储的类型
interface的变量里面可以存储任意类型的数值,如何获取改变量里面实际保存了哪个类型的对象,下面我们介绍两种方法。go语言有一个语法,可以直接判断是否是该类型的变量:value,ok = element.(T),这个value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型。如果element里面确实存储了T类型的数值,那么ok返回true,否则返回false。
8.反射
反射就是能检查程序在运行时的状态,go语言反射一般分三步走:
第一步:要去反射一个类型的值,首先把它转换成reflect对象,比如reflect.Type,reflect.Value,代码如下:
//得到类型的元数据,通过t能获取类型定义里面的所有元素
t := reflect.TypeOf(i)
//得到实际的值,通过v获取存储在里面的值,还可以去改变值
t := reflect.ValueOf(i)
第二步:转化为reflect对象之后,然后将reflect对象转化成相应的值:
//获取定义在struct里面的标签
tag := t.Elem().Field(0).Tag
//获取存储在第一个字段里面的值
name := v.Elem().Field(0).String()
//获取反射值能返回相应的类型和数值
var x int32=24
v := reflect.ValueOf(x);
fmt.Println("type:",v.Type())//type: int32
fmt.Println("kind is int:",v.Kind() == reflect.Int32)//kind is int: true
fmt.Println("value:",v.Int())//value: 24
//反射的字段必须是可修改的,也就是说反射的字段可以读写。修改一个字段的值代码如下:
var x float64 = 24.1
p := reflect.ValueOf(&x)
v := p.Elem()
v.SetFloat(7.1)
最后,上面阐释了go interface一般使用,还有一些遗漏就不一一举例,希望大家能受益。