- 数组是定长的数据结构,长度一旦指定后就不能改变。
- 切片不是定长的,切片容量不够会自行扩容。
1 数组
- 使用场景:事先知道要存放的数据长度,并且明确在后续的过程中,数组不需要扩容。(
数组长度是定长的,在声明数组的时候就已经将数组长度确定下来,后续也无法更改数组长度) - 类型:数组是值类型,而非引用类型,所以在函数传参的过程中,是进行整个数组的值拷贝。
1.1 数组初始化
- 数组声明的长度只能是常量,不能使用变量。(必须明确长度)
go
var a [10]int
- 使用元素初始化
go
nums := [5]int{1, 2, 3}
- 编译器自动判断数组长度
go
//如果省略号没有,则声明的是切片
nums := [...]int{1, 2, 3}
- 通过
new关键字生成指针
go
//该方式得到的是一个指针
nums := new([5]int)
1.2 数组的使用
- 获取数组元素:通过数组下标获取某个位置的元素。
go
import "fmt"
func main() {
nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(nums[0])
}
- 修改数组元素
go
import "fmt"
func main() {
nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(nums[0])
nums[0] = 10
fmt.Println(nums[0])
}
//输出结果
//1
//10
- 获取数组长度:使用内置函数
len
go
import "fmt"
func main() {
nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(len(nums))
}
- 获取数组容量:使用内置函数
cap,数组中,容量和长度是一样的,但在切片中,长度和容量的值不一定一样。
go
import "fmt"
func main() {
nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(cap(nums))
}
-
数组切割
- 数组切割的格式:
arr[startIndex:endIndex],区间为左闭右开。
goimport "fmt" func main() { nums := [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println(nums[:3]) //[1 2 3] fmt.Println(nums[3:]) //[4 5 6 7 8 9] fmt.Println(nums[2:3]) //[3] slice := nums[:] fmt.Println(slice) //[1 2 3 4 5 6 7 8 9],转换后的数组类型转变成切片类型,和原数组指向的的同一个内存地址 slice[0] = 10 //切片元素修改,原数组也会修改 fmt.Println("数组:", nums) //数组: [10 2 3 4 5 6 7 8 9] fmt.Println("切片:", slice) //切片: [10 2 3 4 5 6 7 8 9] } - 数组切割的格式:
2 切片
2.1 切片的初始化
go
var nums []int // 值
nums := []int{1, 2, 3} // 值
nums := make([]int, 0, 0) // 值
nums := new([]int) // 指针
-
使用
make创建切片gonums := make([]int, 0, 0)-
三个参数:类型,长度,容量
-
长度和容量的区别:
-
长度:现有切片的元素长度。
-
容量:切片总共能装的元素数量。
-
-
-
切片和数组最大区别是,切片可以自动扩张容量。
-
声明切片时,值为
nil,不会为其分配内存空间。govar nums []int //只声明,不会为其分配内存
2.2 切片的使用
- 切片的使用和数组的使用基本一致。
- 切片可以使用
append函数为切片添加元素。
go
import "fmt"
func main() {
nums := make([]int, 1)
nums = append(nums, 1, 2, 3, 4, 5)
fmt.Println(nums)
}
-
切片的自动扩容
-
golang1.18 版本之前
- 当原来的切片容量小于1024时,新的切片容量扩容为原来的2倍。
- 当原来的切片容量大于1024时,新的切片容量扩容为原来的1.25倍。
-
golang1.18 版本之后
- 当原来的切片容量小于256时,新的切片容量扩容为原来的2倍。
- 当原来的切片容量大于256时,新的切片容量扩容公式为:newcap = oldcap+(oldcap+3*256)/4
-
2.3 插入元素
切片的插入结合append函数。
- 头部插入
go
import "fmt"
func main() {
nums := []int{1, 2}
nums = append([]int{-2, -1, 0}, nums...)
fmt.Println(nums)//[-2 -1 0 1 2]
}
- 中间插入
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums[:3+1], append([]int{999, 999}, nums[3+1:]...)...)
fmt.Println(nums)//[1 2 3 4 999 999 5 6 7 8 9]
}
- 尾部插入
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums, 99, 100)
fmt.Println(nums)//[1 2 3 4 5 6 7 8 9 99 100]
}
2.4 删除元素
切片的删除结合append函数。
- 头部删除
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums[2:])
fmt.Println(nums) //[3 4 5 6 7 8 9]
}
- 中间删除
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums[:1], nums[2:]...)
fmt.Println(nums)//[1 3 4 5 6 7 8 9]
}
- 尾部删除
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums[:1])
fmt.Println(nums)
}
- 全部删除
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums = append(nums[:0])
fmt.Println(nums)
}
2.5 拷贝
使用copy函数。
- 注意:确保目标切片的长度足够长。
go
func main() {
dest := make([]int, 15)//目标切片长度必须够长,不然无法完成完整的拷贝
src := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(src, dest)
fmt.Println(copy(dest, src))
fmt.Println(src, dest)
}
2.6 切片的遍历
for遍历
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
for i := 0; len(nums) > i; i++ {
fmt.Println(nums[i])
}
}
for range遍历
go
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
for i, v := range nums {
fmt.Println("index:", i, " value:", v)
}
}
2.7 多维切片
- 多维切片和多维数组不一样的点在于,多维切片,每个维度需要单独遍历初始化。
go
import "fmt"
func main() {
square := [][]int{{1, 2}, {2, 3}, {3, 5}}
for _, sq := range square {
fmt.Println("square:", sq)
for _, h := range sq {
fmt.Print(" ", h, "")
}
fmt.Println()
}
}
2.8 拓展表达式
-
切片与数组都可以使用简单表达式来进行切割,但是拓展表达式只有切片能够使用。
-
主要是为了解决切片共享底层数组的读写问题。需要满足关系
low<= high <= max <= cap,使用拓展表达式切割的切片容量为max-low。
slice[low:high:max]
- low:开始下标
- high:结束下标
- max:表示新切片可以获取到最大的原切片的容量大小
-
扩展表达式的作用
- 问题:一个切片进行切割,得出新切片和原切片公用的底层是同一个数组,对新切片进行数据操作,会对原切片的数据进行修改。
gofunc main() { oldSlice := []int{1, 2, 3, 4, 5, 6} newSlice := oldSlice[2:3] //未指定切片的最大下标,默认使用就切片容量大小,此时cap:6-2=4 fmt.Println(newSlice) //输出新切片:[3] newSlice = append(newSlice, 100) //新切片添加元素:100 //输出:newSlice: [3 100] oldSlice: [1 2 3 100 5 6] fmt.Println("newSlice:", newSlice, " oldSlice:", oldSlice) }

- 修改:切片的切割增加max参数
go
func main() {
oldSlice := []int{1, 2, 3, 4, 5, 6}
newSlice := oldSlice[2:3:3] //指定新切片的最大下标,此时cap:3-2=1
fmt.Println(newSlice, cap(newSlice)) //[3] 1
newSlice = append(newSlice, 100) //新切片添加元素:100
//newSlice: [3 100] oldSlice: [1 2 3 4 5 6]
fmt.Println("newSlice:", newSlice, " oldSlice:", oldSlice)
}

-
原理:
当切片切割时,指定了max=3时,切割后获得的新切片的容量为1,当新切片添加新的值,此时新切片的容量不够,此时会给新切片分配一个新的数组,对新切片操作就不会修改到原切片的值。
2.9 clear函数
- clear函数会将切片内所有的值置为零
go
import (
"fmt"
)
func main() {
s := []int{1, 2, 3, 4}
clear(s)
fmt.Println(s)
}