数组和Slice(切片)

数组

数组是固定长度相同类型的集合。数组的长度必须是一个常量表达式(编译阶段就知道结果),数组元素的值可以由地址下标访问和修改的。 数组是比较特殊的类型,数组的长度是数组类型的一部分,像[3]int[6]int二者是不同类型

var a [3]int
var b []string


var c = [5]int{1, 2, 15, 23, 16}
var d = [...]int{9, 6, 7, 5, 12} // `...`可以替代写具体长度,编译器可以帮你算 

数组遍历

数组可以使用forfor range方式来遍历

var arr = [9]int{0, 1}
for i := 0; i < len(arr); i++ {
	arr[i] = i * 2
}

for _, v := range arr {
	fmt.Println(v)
}

for i, _ := range arr {
	fmt.Println(arr[i])
}

数组在golang中实践使用的比较少,很多场景中我们都使用Slice来替代。

切片(slice)

切片是对数组一段连续内存的引用,在golang中Slice的底层结构为

type SliceHeader struct {
	Data uintptr   //指向该切片的索引的底层数组中的起始位置
	Len  int //切片长度
	Cap  int //切片总容量
}

内置函数lencap可以分别获取切片的长度和大小。

切片的内存模型

var a=[5]int{1,2,3,4,5}
b:=a[0:3] // b SliceHeader{&a[0],3,5}
c:=a[3:5]// c SliceHeader{&a[3],2,2}

切片表达式

var a=[5]int{1,2,3,4,5}
b:=a[:3] //等同于 a[0:3]
c:=a[3:] //等同于 a[3:5]
d:=a[:] //等同于 a[0:5]

使用make 创建

a := make([]int, 8, 9) //创建[]int且切片 len为8 cap为9 
aa := make([]int, 8) //参数cap可以省略 默认cap和len一样

切片的复制

golang内置函数copy来复制切片

copy的声明格式func copy(dist []T,src []T)int ,copy的返回值为拷贝的长度

src1 := []int{1, 2, 3}
src2 := []int{4, 5}
dest := make([]int, 5)

n := copy(dest, src1) //注意这边只拷贝了前三个元素
n = copy(dest[3:], src2) //拷贝从第四个位置上

切片追加

golang内置函数append来追加切片。

append声明格式func append(dest[]T, x ...T) []T

append方法将多个具有相同类型的元素追加到dest切片后面并且返回新的切片,追加的元素必须和dest切片的元素同类型。

如果dest的切片容量不够,append会分配新的内存来保证已有切片元素和新增元素的存储。因此返回的切片所指向的底层数组可能和dest所指向的底层数组不相同。

a := []int{1, 2, 3} //a len:2 cap:3
b = append(a, 4, 5, 6) //b: len:5 cap:5 b和a指向的数组已经不同 

c := append(a,b...) // 使用...快速展开b

切片遍历

切片遍历和数组基本上没差别

var arr = make([]int,10)
for i := 0; i < len(arr); i++ {
	arr[i] = i * 2
}

for _, v := range arr {
	fmt.Println(v)
}

for i, _ := range arr {
	fmt.Println(arr[i])
}