简单记录一下Go的数组和切片(还有很多有关这两种复合类型的细节没讲,这里只是简单说明):
1.数组
数组的类型名是[n]elementType,其中n是数组长度,elementTyp是数组元素类型。一般初始化有下面几种:
a := [5]int{1, 2, 3, 4, 5} //定义了一个长度为5的int型数组
a := [...]int{1, 2, 3, 4, 5} //不指定长度,但根据后面的初始化列表数量就可以确定其长度
a := [3]{1:1,2:3} //指定总长度,并且根据索引值来初始化值a[0,1,3]
a := [...]int{1:1,2:3} //不指定总长度,根据索引值来初始化,并且根据最后一个值确定数组长度 a := new([10]int) //通过内置函数new函数来创建数组,与上面不同的是该创建方式得到的值是指针
数组创建完之后长度就固定了,不可以再追加元素,数组长度可以使用内置函数len来获取,需要注意的是初始化数组长度必须是常量表达式,下面是错误初始化例子:
length := 5 //这是一个变量
a:=[length]int
数组还能进行切割,切割数组的格式为arr[startIndex:endIndex],切割区间是左开右闭区间,例如:
var a = [5]int{1, 2, 3, 4, 5}
fmt.Println(a[0:4]) //[1,2,3,4]
fmt.Println(a[:3]) //[1,2,3]
fmt.Println(a[3:]) //[4,5]
2.切片
切片就是一种变长数组,数据结构中有指向数组的指针,其实是一种引用类型,换句话来说,切片的底层依旧是数组,Go为切片维护以下三个元素:
type slice struct {
array unsafe.Pointer //指向底层数组的指针
len int //切片的元素数量
cap int //底层数组的容量
}
切片的初始化有以下几种:
var nums []int // 值
nums := []int{6, 5, 4} // 值
nums := make([]int, 0, 0) // 值
nums := new([]int) // 指针
其中通过内置函数make创建切片可以确定其长度和容量,值得注意的是第一种初始化是被允许的,但以下声明是不被允许的:
a := make([]int)
这提示我们在用内置函数make创建切片时,一定要声明它的长度,容量可选择声明也可以不声明。
插入元素
切片元素的插入也是需要结合appned函数来使用,例如:
nums := make([]int, 0, 0) //创建一个长度和容量均为0的切片
nums = append(nums, 1, 2, 3, 4, 5, 6, 7) //往目标切片nums添加元素 [1,2,3,4,5,6,7]
fmt.Println(len(nums), cap(nums)) //此时切片长度为7,容量为8
在尾部插入元素,就是append最原始的方法,当然也可以在头部和中间插入元素,合理使用append函数就可实现
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
nums = append(nums, 99, 100)
fmt.Println(nums) // [1 2 3 4 5 6 7 8 9 10 99 100]
删除元素
同样可以使用append函数来对切片里的元素进行删除操作。
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
nums = nums[n:]
fmt.Println(nums) //n=3 [4 5 6 7 8 9 10]
这里简单说明一下有关切片的拓展表达式,其格式为:
slice[low:high:max]
low和high的含义与上述数组分割一样,而max则是指最大的容量,如下面的例子则是省略了max,s2的容量其实是cap(s1)-low
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8} //cap(s1) = 8
s2 := s1[3:4] //[4]
fmt.Println(cap(s2)) //实际容量为cap(s1) - low = 8 - 3 = 5
这样赋值后,s1和s2共享同一个底层数组,在对s2进行读写操作时,也可能会对s1进行修改,例如:
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9,10} // cap = 10
s2 := s1[3:4] // cap = 10 - 3 = 7
// 添加新元素,由于容量为7.所以没有扩容,直接修改底层数组
s2 = append(s2, 1)
fmt.Println(s2) //[4,1]
fmt.Println(s1) //[1,2,3,4,1,6,7,8,9,10]
上述问题中本来要修改s2的值,但同时修改了s1的值,此时要想解决这个问题就可以使用拓展表达式,控制s2的最大容量即可:
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9,10} // cap = 10
s2 := s1[3:4:4] // cap = 4 - 3 = 1
// 容量不足,分配新的底层数组
s2 = append(s2, 1)
fmt.Println(s2) //[4,1]
fmt.Println(s1) //[1,2,3,4,5,6,7,8,9,10]