获取 slice 长度 #
通过前面关于 slice 的文章,我们知道了 slice header 的结构体定义:
1 2 3 4 5 6 | // runtime/slice.go type slice struct { array unsafe.Pointer // 元素指针 len int // 长度 cap int // 容量 } |
调用 make 函数新建一个 slice,底层调用的是 makeslice 函数,返回的是 slice 结构体:
1 | func makeslice(et *_type, len, cap int) slice |
因此我们可以通过 unsafe.Pointer 和 uintptr 进行转换,得到 slice 的字段值。
1 2 3 4 5 6 7 8 | func main() { s := make([]int, 9, 20) var Len = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(8))) fmt.Println(Len, len(s)) // 9 9var Cap = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(16))) fmt.Println(Cap, cap(s)) // 20 20 } |
Len,cap 的转换流程如下:
1 2 | Len: &s => pointer => uintptr => pointer => *int => int Cap: &s => pointer => uintptr => pointer => *int => int |
获取 map 长度 #
再来看一下上篇文章我们讲到的 map:
1 2 3 4 5 6 7 8 9 10 11 12 13 | type hmap struct { count int flags uint8 B uint8 noverflow uint16 hash0 uint32buckets unsafe.Pointer oldbuckets unsafe.Pointer nevacuate uintptrextra *mapextra } |
和 slice 不同的是,makemap 函数返回的是 hmap 的指针,注意是指针:
1 | func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap |
我们依然能通过 unsafe.Pointer 和 uintptr 进行转换,得到 hamp 字段的值,只不过,现在 count 变成二级指针了:
1 2 3 4 5 6 7 8 | func main() { mp := make(map[string]int) mp["qcrao"] = 100 mp["stefno"] = 18count := **(**int)(unsafe.Pointer(&mp)) fmt.Println(count, len(mp)) // 2 2 } |
count 的转换过程:
1 | &mp => pointer => **int => int |