切片是动态数组,比数组灵活。数组长度不可变,但是切片可以追加。 切片原型定义如下:
struct Slice
{
byte *array;
unit32 len;
unit32 cap;
};
它抽象为以下三个部分:
1. 指向被引用的底层数组的指针;
2. 切片中元素的个数;
3. 切片分配的存储空间。
声明、定义和初始化
声明一个切片:
var sliceTest []int
- 声明的切片是nil,不初始化无法插入数据
- 跟map一样,通过make定义切片
make([]T, length, capacity)
- length为初始长度,为必须参数。capacity为指定容量,可选。
例如:
sliceTest = make([]int, 10)
- 直接初始化切片
sliceTest1 := [] int {1,2,3}
- 引用赋值
s := arr[startIndex:endIndex]
初始化s,是arr从startIndex到endIndex的引用
s := sliceTest1[:]//s表示sliceTest的引用
s1 := sliceTest[1]
append
- append主要用于给某个切片(slice)追加元素
- 如果该切片存储空间(cap)足够,就直接追加,长度(len)变长;如果空间不足,就会重新开辟内存,并将之前的元素和新的元素一同拷贝进去
- 第一个参数为切片,后面是该切片存储元素类型的可变参数
代码例子
package main
import (
"fmt"
)
func main(){
var sliceTest []int
//声明的切片是nil
if sliceTest == nil {
fmt.Println("slice is nil")
}
//用make创建切片,制定默认长度
sliceTest = make([]int, 2)
sliceTest[0] = 1
fmt.Printf("len:%d, cap:%d\n", len(sliceTest), cap(sliceTest))
sliceTest[1] = 2
//通过range遍历切片
for i, v := range sliceTest{
fmt.Printf("index:%d, value:%d\n", i, v)
}
//切片默认长度是2,不能直接通过下标增加长度
//sliceTest[2] = 2 //程序崩溃,提示"panic: runtime error: index out of range"
//sliceTest[3] = 3
//通过append添加元素到切片中
sliceTest = append(sliceTest, 3)
fmt.Printf("len:%d, cap:%d\n", len(sliceTest), cap(sliceTest))//第一次append将cap增加了2
sliceTest = append(sliceTest, 4)
fmt.Printf("len:%d, cap:%d\n", len(sliceTest), cap(sliceTest))//第二次append,因为还有空间,cap没增加
for i := 0; i < len(sliceTest); i++ {
fmt.Printf("index:%d, value:%d\n", i, sliceTest[i])
}
s := sliceTest[:]//s引用sliceTest
fmt.Printf("s, len:%d, cap:%d\n", len(s), cap(s))
for i := 0; i < len(s); i++ {
fmt.Printf("s, index:%d, value:%d\n", i, s[i])
}
s1 := s[2:4]//s1引用s下标2-4的元素(不包含下标4)
fmt.Printf("s1, len:%d, cap:%d\n", len(s1), cap(s1))
for i := 0; i < len(s1); i++ {
fmt.Printf("s1, index:%d, value:%d\n", i, s1[i])
}
s1[1] = 14 //改变s1中的值
for i := 0; i < len(sliceTest); i++ {
fmt.Printf("sliceTest, index:%d, value:%d\n", i, sliceTest[i])//因为切片是引用类型,所以修改会反应到sliceTest中
}
s2 := s[:2]
fmt.Printf("s2, len:%d, cap:%d\n", len(s2), cap(s2))
for i := 0; i < len(s2); i++ {
fmt.Printf("s2, index:%d, value:%d\n", i, s2[i])
}
s2 = append(s2, 23)//s2的cap=4,len=2,空间充足,直接追加
fmt.Printf("s2, len:%d, cap:%d\n", len(s2), cap(s2))
for i := 0; i < len(sliceTest); i++ {//sliceTest跟s2指向同一个slice,所以
fmt.Printf("sliceTest, index:%d, value:%d\n", i, sliceTest[i])
}
s2 = append(s2, 24)
fmt.Printf("s2, len:%d, cap:%d\n", len(s2), cap(s2))
for i := 0; i < len(sliceTest); i++ {
fmt.Printf("sliceTest, index:%d, value:%d\n", i, sliceTest[i])
}
for i := 0; i < len(s2); i++ {
fmt.Printf("s2, index:%d, value:%d\n", i, s2[i])
}
s3 := append(s2, 25, 26, 27)//s2继续添加,因为容量不够,所以要从新分配内存,将之前的元素copy过去,再赋值给s3。此时s2没有变,还是sliceTest的引用
s2[0] = 21//此时更改s2[0],会更改到sliceTest[0]
s3[0] = 31//此时更改s3[0],不会更改到sliceTest[0]
fmt.Printf("s2, len:%d, cap:%d\n", len(s2), cap(s2))
fmt.Printf("s3, len:%d, cap:%d\n", len(s3), cap(s3))
for i := 0; i < len(sliceTest); i++ {
fmt.Printf("sliceTest, index:%d, value:%d\n", i, sliceTest[i])
}
for i := 0; i < len(s2); i++ {
fmt.Printf("s2, index:%d, value:%d\n", i, s2[i])
}
for i := 0; i < len(s3); i++ {
fmt.Printf("s3, index:%d, value:%d\n", i, s3[i])
}
}