Golang源码研究:3. unsafe包

文章内容

使用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))} 

已有 1 人为这篇文章点赞

分类:Golang 源码研究

评论 (0)

无需注册,留言经站长审核后公开。

加载评论中…

Golang源码研究:3. unsafe包 · Ensan 的博客