数组
- 从两个维度描述数组,1数组中存储的元素类型2数组最大能存储的元素个数,用如下所示的方式来表示数组类型:
- 声明:
1.[10]int
2.[200]interface{}
- 数组在初始化之后大小就无法改变。存储元素类型相同、大小不同的数组类型在 Go 语言看来也是完全不同的,只有两个条件都相同才是同一类型。
- 初始化:
1.显式的指定数组大小arr1 := [3]int{1, 2, 3}
2.使用 […]T 声明数组,Go 语言会在编译期间通过源代码推导数组的大小arr2 := [...]int{1, 2, 3}
- 如果数组中元素的个数小于或者等于 4 个,那么所有的变量会直接在栈上初始化,如果数组元素大于 4 个,变量就会在静态存储区初始化然后拷贝到栈上,这些转换后的代码才会继续进入中间代码生成和机器码生成两个阶段,最后生成可以执行的二进制文件。
切片
- 动态数组,其长度并不固定,我们可以向切片中追加元素,它会在容量不足时自动扩容。
- 声明:
1.[]int
2.[]interface{}
- 数据结构
Data 是指向数组的指针;
Len 是当前切片的长度;
Cap 是当前切片的容量,即 Data 数组的大小:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
- 初始化
1通过下标的方式获得数组或者切片的一部分;
2使用字面量初始化新的切片;
3使用关键字 make 创建切片:
arr[0:3] or slice[0:3]
slice := []int{1, 2, 3}
slice := make([]int, 10)
其中使用字面量初始化过程:
1根据切片中的元素数量对底层数组的大小进行推断并创建一个数组;
2将这些字面量元素存储到初始化的数组中;
3创建一个同样指向 [3]int 类型的数组指针;
4将静态存储区的数组 vstat 赋值给 vauto 指针所在的地址;
5通过 [:] 操作获取一个底层使用 vauto 的切片;
- 追加
slice = append(slice, 1, 2, 3)
- 扩容
func growslice(et *_type, old slice, cap int) slice {
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
在分配内存空间之前需要先确定新的切片容量,运行时根据切片的当前容量选择不同的策略进行扩容:
1如果期望容量大于当前容量的两倍就会使用期望容量;
2如果当前切片的长度小于 1024 就会将容量翻倍;
3如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;
- 拷贝
copy(a,b)