反射来自元编程,指通过类型检查变量本身数据结构的方式,只有部分编程语言支持反射。
Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。
在什么情况下需要反射
- 不能明确接口调用哪个函数,需要根据传入的参数在运行时决定。
- 不能明确传入函数的参数类型,需要在运行时处理任意对象。
类型
反射构建在类型系统之上,Go是静态类型语言,每一个变量都有静态类型,在编译时就确定下来了。
比如
type MyInt int
var i int
var j MyInt
i和j的底层类型都是int
,但i的静态类型是int
,j的静态类型是MyInt
,这两个是不同类型,是不能直接赋值的,需要类型强制转换。
掌握reflect包的以下函数:
- reflect.ValueOf({}interface) reflect.Value:获取某个变量的值,但值是通过reflect.Value对象描述的。
- reflect.TypeOf({}interface) reflect.Type:获取某个变量的静态类型,但值是通过reflect.Type对象描述的,是可以直接使用Println打印的。
- reflect.Value.Kind() Kind:获取变量值的底层类型(类别),注意不是类型,是Int、Float,还是Struct,还是Slice,具体见此。
- reflect.Value.Type() reflect.Type:获取变量值的类型,效果等同于reflect.TypeOf。
再解释下Kind和Type的区别
type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)
v.Kind()得到的是Int,而Type得到是MyInt。
反射原理
反射的意思是在运行时,能够动态知道给定数据对象的类型和结构,并有机会修改它!
现在一个数据对象,如何判断它是什么结构?
数据interface中保存有结构数据呀,只要想办法拿到该数据对应的内存地址,然后把该数据转成interface,通过查看interface中的类型结构,就可以知道该数据的结构了呀~
如何实现字符串和byte切片的零拷贝
func string2bytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s))
}
func bytes2string(b []byte) string{
return *(*string)(unsafe.Pointer(&b))
}
原理上是利用指针的强转