使用unsafe包修改私有成员
在go中,私有成员是不允许在外部更改的,但是我们可以通过go提供的unsafe.offset做偏移计算从而修改私有成员。
go
type Programmer struct { name string langauge string} func main() { p := Programmer{"sanenchen", "golang"} fmt.Println(p) name := (*string)(unsafe.Pointer(&p)) *name = "jing" lang := (*string)(unsafe.Add(unsafe.Pointer(&p),unsafe.Offsetof(p.langauge))) *lang = "Java" fmt.Println(p)} 输出如下
plain text
{sanenchen golang}{jing Java}利用unsafe获取silce和map长度
根据上文所说的,通过unsafe直接获取私有成员的值,array 作为一个指针,指向所属的底层数组。
占用内存为8字节(64位系统),通过分别偏移8字节和16字节,即可获取到len和cap的值。
go
/*// 这里源码在 runtime/silce.go type slice struct { array unsafe.Pointer // 8 byte len int cap int }*/func main() { s := make([]int, 9, 20) // type len cap Len := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + 8)) Cap := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + 16)) fmt.Println(Len, len(s)) fmt.Println(Cap, cap(s))}实现字符串和byte切片零复制转换
go
/*string与slice零拷贝转换,理论上共享Data数组即可type StringHeader struct { Data uintptr Len int}type SliceHeader struct { Data uintptr Len int Cap int}*/func string2bytes(s string) []byte { // return *(*[]byte)(unsafe.Pointer(&s)) 通过指针强制转换 return unsafe.Slice(unsafe.StringData(s), len(s)) // go 1.20 后提供的api} func bytes2string(b []byte) string { // return *(*string)(unsafe.Pointer(&b)) return unsafe.String(unsafe.SliceData(b), len(b))}