Go类型转换内存拷贝优化以及三元符的实现
1.函数实现三元符
注意此方法 参数会执行一遍 且返回需要类型推断
func TriGraph(condition bool, a interface{}, b interface{}) interface{} {
if condition {
return a
} else {
return b
}
}
// 使用
TriGraph(1 > 2, 1, 2) // 返回2
// 若需要使用指定类型方法 需要 接口推断 interface.(需要的类型);switch interface.(type)
2.没有内存拷贝的类型转换
强制类型转换都会导致内存拷贝
- string的本质:reflect.StringHeader{};StringHeader是字符串的运行时表示形式
- slice的本质:reflect.SliceHeader{};SliceHeader是切片的运行时表示
- go指针的本质:unsafe.Pointer{}、uintptr{}
type StringHeader struct { // 字符串的底层结构
Data uintptr
Len int
}
type SliceHeader struct { // 切片的底层结构
Data uintptr
Len int
Cap int
}
1.unsafe.Pointer(&a) 生成unsafe.Pointer指针
2.(*reflect.StringHeader)(unsafe.Pointer(&a)) unsafe.Pointer指针转成底层StringHeader结构的指针
3.(*[]byte)(unsafe.Pointer(&b)) 可以把b底层结构体转成byte的切片的指针
4.再通过 *转为指针指向的内容 之后获取时 通过长度遍历 每个元素的长度由指针类型确定 如[]byte切片 指针每个元素遍历1个字节
a :="aaaa"
b := *(*reflect.StringHeader)(unsafe.Pointer(&a))
c := *(*[]byte)(unsafe.Pointer(&b))
fmt.Printf("%v",c)
string和[]byte直接类型转换;注意字符串转换后的结果只可读不能修改
func byteToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func stringToByte(str string) []byte { // 直接创建的字符串转byte数组 不可修改 且数组长度len与字符串的字节长度一致 切片cap长度没有界限不可用 len:6 cap:824633761944
return *(*[]byte)(unsafe.Pointer(&str))
}
// 直接转换 可以互换
a := "中文test"
bytes := *(*[]byte)(unsafe.Pointer(&a))
// bytes[0] = 11 修改会报错 只读 unexpected fault address xx 因为原数组是字符串的底层数组 字符串不可修改
a = *(*string)(unsafe.Pointer(&bytes))
// 修改限制测试
b := []byte{97}
b = stringToByte(byteToString(b))
b[0] = 99 // 此处可以修改 数组指向程序创建的byte数组 可修改
str := "ztest1"
b = stringToByte(str)
b[0] = 99 // 此处不可修改 数组指向字符串的底层数组 只可读
结构体和[]byte互相转换,用于优化encoding/binary;结构体转byte数组相当于把结构体指针首地址赋值给切片Data
type Test struct {
A int
B int
}
// 获取结构体占用的字节大小 用于len和cap的赋值
var sizeOfStruct = int(unsafe.Sizeof(Test{}))
// 填充[]byte的数据结构 相当于序列化
// 结构体的数据指针int类型
func StructToBytes(t *Test) []byte {
var x reflect.SliceHeader // 切片的底层结构
x.Len, x.Cap = sizeOfStruct, sizeOfStruct
x.Data = uintptr(unsafe.Pointer(t))
return *(*[]byte)(unsafe.Pointer(&x))
}
// 相当于反序列化
// unsafe.Pointer(&b):取[]byte首地址
// (*reflect.SliceHeader)(unsafe.Pointer(&b)) : 强制转换其为reflect.SliceHeader指针
// (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data : 将slice的数据指针取出来
// unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data) : 将uint指针转成任意指针
// (*Test)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data)):成功转换
func BytesToStruct(b []byte) *Test {
return (*Test)(unsafe.Pointer(
(*reflect.SliceHeader)(unsafe.Pointer(&b)).Data))
}