slice 的底层其实是一个结构体:

// go/src/runtime/slice.go
type slice struct {
	array unsafe.Pointer	// slice 的底层数组
	len   int // slice 的长度
	cap   int // slice 的容量
}

make slice 其实返回的是指向这个结构体的指针:

func main() {
    s := make([]int{}, 0, 4)
    fmt.Printf("s 指向结构体的指针: %p\n", s) // 返回指向这个结构体的指针
    fmt.Printf("s 结构体第一个字段的指针: %p\n", &s) // 返回的就是指向 slice.array 的地址,因为结构体的体质就是第一个field 的地址
}

通过 unsafe 包可以获取到 slice 的底层数组的元素、slice 容量、slice 长度:

func main() {
    // 创建底层数组
    array := [4]int{10, 20, 30, 40}
    fmt.Printf("底层数组的指针: %p\n", &array)
    // 使用底层数值创建 slice
    s := array[0:2]
    fmt.Printf("s cap:%d, len:%d, value:%v\n", cap(s), len(s), s)
    fmt.Println("获取 slice 的长度:", *(*int)(unsafe.Pointer((uintptr(unsafe.Pointer(&s)) + 8))))
    fmt.Println("获取 slice 的容量:", *(*int)(unsafe.Pointer((uintptr(unsafe.Pointer(&s)) + 16))))

    // 获取 slice 底层数组的值
    // step 1: 先获取到 slice 结构体底层数组的 unsafe.Pointer 值,即 slice.array
    s_array_unsafe_pointer := unsafe.Pointer(&s)
    // step 2: 通过 s_array_unsafe_pointer 获取到底层数组的指针
    s_array_pointer := *((*unsafe.Pointer)(s_array_unsafe_pointer))
    fmt.Println("unsafe 获取到的底层数组的指针:", s_array_pointer)
    // step 3: 通过底层数组的指针即可获取到值
    fmt.Println("unsafe 获取 slice 底层数组的值:", *(*[4]int)(s_array_pointer))
    fmt.Println("unsafe 获取 slice 底层数组第一个值:", *(*int)(s_array_pointer))
    fmt.Println("unsafe 获取 slice 底层数组第二个值:", *(*int)(unsafe.Pointer((uintptr(s_array_pointer) + 8*1))))
    fmt.Println("unsafe 获取 slice 底层数组第三个值:", *(*int)(unsafe.Pointer((uintptr(s_array_pointer) + 8*2))))
    fmt.Println("unsafe 获取 slice 底层数组第四个值:", *(*int)(unsafe.Pointer((uintptr(s_array_pointer) + 8*3))))
}