go基础 - 反射、 低级编程
- reflect.TypeOf返回一个接口值对应的动态类型
基础类型
- Bool
- String
- 各种数字类型
聚合类型
- Array
- Struct
引用类型
- Chan
- Func
- Ptr
- Slice
- Map
接口类型
- Interface
- Invalid 类型
- 注意、即使非导出字段在反射下也是可见的
x := 2
a := reflect.ValueOf(2)
b := reflect.ValueOf(x)
c := reflect.ValueOf(&x)
d := c.Elem()
- a 里边的值是不可寻址的, 它包含的仅仅是整数2的一个副本
- 可以通过CanAddr方法来询问reflect.Value 变量是否可寻址
- 从一个可寻址的reflect.Value()获取变量需要三步,首先调用addr(), 返回一个Value, 其中包含一个指向变量的指针,接下来在这个Value调用Interface(),会返回一个包含这个指针的interface{}值,最后如果我们知道变量的类型,我们可以使用类型断言来把接口内容转换为一个普通指针,之后就可以通过这个指针来更新变量了
- CanAddr来检查并不能保证正确,CanSet方法才能正确地报告一个reflect.Value是否可寻址且更改
- 要调用req.ParseForm() req.Form才会有内容
- 使用reflect.Value.Call 方法可以调用Func类型的Value
反射注意事项
- 反射代码脆弱,不能再编译时完成检测
- 在包的API避免使用reflect.Value 尽量使用特定的类型来确保输入是合法的值,如果做不到这点就需要在每个危险操作前都做额外的动态检查
- 类型其实也算某种形式的文档,反射相关的操作无法做静态类性检查,所以大量使用反射的代码是很难理解的。
- 反射很慢
- 32位上字的长度是4字节 64位是8字节
- 语言规范并没有要求成员的顺序对应内存中的布局顺序
- 将相同类型的成员定义在一起可以更节约内存空间(内存对齐)
- unsafe.Alignof 报告它参数类型是所要求的对齐方式
- unsafe.Offsetof 计算成员f相对于x其实地址的偏移值
- 不要把指针转换成uintptr 再进行 操作 建议一次执行完毕,因为有可能在执行的过程中发生Go gc导致内存地址变更 而uintptr无法及时更新
go调用c
- 利用cgo
- 利用SWIG