Go语言中的接口和反射
接口 interface
接口就是一个或多个方法的集合,若某个类型的对象实现了所有的方法,那么这个对象就实现了这个接口
接口还可以存储值,只要这个类型的对象实现了这个接口,那么这个接口就可以存储这个类型的对象
又因为空接口(interface{})没有一个方法,每个类型的对象至少实现了0个或者0个以上的方法,所以空接口能存储任何值
既然接口可以被很多对象实现,那么接口就可以存储很多类型的对象或值,那函数的形参就可以用 接口类型,这样函数就可以接收实现了这个接口的多种类型的对象或值
那现在有一个以接口为形参的函数,要怎么知道这个接口是什么类型的呢?
我们可以这样判断,加入函数的形参是一个接口B类型的值b,我们需要知道b是不是A类型的,并且判断A对象是否实现了B接口
我们可以使用接口中的 .(type) 来判断类型
1 | func test(b B) { |
当前,形参也可以是空接口
空接口可以接收任何值,一个小例子
1 | var x float32 = 5.3 |
内嵌接口
和结构体中的匿名类型差不多
io包中的Writer和Reader
1 | type Reader interface { |
反射 reflection
从接口值到反射对象
类型-值
Type Value
reflect.TypeOf() 获取的是reflect.Type
reflect.ValueOf() 获取的是reflect.Value
1 | // TypeOf 返回 interface{} 中的值的反射类型Type |
接收参数的空接口类型(interface{}),因为任何值都有0个或0个以上的方法,可以说都实现了空接口,可以空接口可以接收任何值
reflect中有一个Kind方法,Kind() 和 TypeOf()都是返回类型,但是又有区别
1 | type myInt int |
会输出
1 | Type: main.myInt Kind: int |
Type能识别自定义的类型,Kind只能识别到底层的类型
关于结构体的反射对象到值
一个简单的例子(取自官方文档)
1 | type T struct { |
输出
1 | 0: A int = 23 |
从反射对象到接口值
给了一个 reflect.Value
有一个方法
1 | func (v Value) Interface() interface{} |
例如
1 | var x int = 5 |
要修改反射对象,其值必须可设置
1 | var x float64 = 5.4 |
调用SetFloat()之后会报panic
1 | panic: reflect: reflect.Value.SetFloat using unaddressable value |
无论是想改x,还是x的副本a 这样都无法修改
但是如果想修改x,可以这样
1 | var x float64 = 5.4 |
输出
1 | c: 11.1 x: 11.1 |