獲取 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 9 var 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 uint32 buckets unsafe.Pointer oldbuckets unsafe.Pointer nevacuate uintptr extra *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"] = 18 count := **(**int)(unsafe.Pointer(&mp)) fmt.Println(count, len(mp)) // 2 2 } |
count 的轉換過程:
1 |
&mp => pointer => **int => int |