Golang Slice笔记
Little_YangYang

本笔记旨在记录Go语言中的底层内容学习过程,仅代表个人学习记录,阅读请注意鉴别版本及特性。

Slice 结构体

1
2
3
4
5
type slice struct {  
array unsafe.Pointer
len int
cap int
}

array是一个unsafe的指针,指向的是底层存储元素的连续内存数组的起始位置。

len是切片的长度,即该slice所包含的元素数量,可通过len()函数访问。

cap是当前切片的容量,即从array指针开始,底层数组可以容纳的元素总量,可通过cap()函数访问。

一个切片变量本身只占用3个机器字节长度的大小,对切片进行切片操作,只会创建一个新的slice结构体,而不会拷贝底层数组的数据,该操作虽然效率很高,但也导致在这处会出现陷阱问题。

Slice创建

1
2
3
4
5
6
7
8
9
10
11
12
func makeslice(et *_type, len, cap int) unsafe.Pointer {  
mem, overflow := math.MulUintptr(et.Size_, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap {
mem, overflow := math.MulUintptr(et.Size_, uintptr(len))
if overflow || mem > maxAlloc || len < 0 {
panicmakeslicelen()
}
panicmakeslicecap()
}

return mallocgc(mem, et, true)
}

et *_type: 描述切片元素类型的内部结构体,包含了元素大小、是否包含指针等信息。

len, cap: 用户指定的长度和容量。

执行时先检查创建安全性,如len < 0len > cap,以及计算出的总内存大小et.Size_ * cap是否溢出或超出最大内存分配限制maxAlloc,然后调用 mallocgc在堆上分配一块连续的内存,最后返回新分配内存的起始地址 unsafe.Pointer

编译器会用这个指针、lencap 来填充最终的 slice 结构体。

根据golang.org/issue/4085所述,为了更加清晰易懂,若出现make([]T, bignumber)过大的情况,应使用“len out of range”来替代“cap out of range”