【入门】Go语言切片详解
目录
一、Go语言切片简介
1.1 切片的概念
数组和切片相比较切片的长度是不固定的,可以追加元素,在追加时可能会使切片的容量增大,所以可以将切片理解成 "动态数组",但是,它不是数组。
1.2 数组和切片的区别是什么?
- 数组的长度是固定的,切片的长度是可变的。
- 数组在声明时需要指定长度,切片不需要。
- 数组的长度是数组类型的一部分,因此 [5]int 和 [10]int 是不同的类型,不能互相赋值或比较。而切片只需要考虑元素类型,因此 []int 和 []float64 是相同的类型。
- 数组是值类型,当数组作为参数传递时,会被复制一份,因此对数组的修改不会影响原数组。而切片是引用类型,当切片作为参数传递时,只会传递一个指向底层数组的指针,因此对切片的修改会影响原切片。
- 数组的长度是固定的,在内存中占用连续的空间。而切片的长度是可变的,在内存中是一个结构体,其中包含指向底层数组的指针、长度和容量三个字段。
二、切片声明
2.1 使用var声明切片
语法:
var 切片名称[]数据类型
举个例子:
var arr []int
2.2 使用自动推导类型声明切片
语法:
切片名称 := []类型{}
举个例子:
arr := []int{}
2.3 使用make()函数生成切片
语法:
make([]类型, 长度, 容量)
- 长度是已初始化空间
- 容量是已经开辟空间,包括已经初始化的空间和空闲空间。
举个例子:
package main
import "fmt"
func main() {
arr := make([]int, 3, 5)
fmt.Printf("长度:%d\t容量:%d", len(arr), cap(arr))
}
代码输出内容:
长度:3 容量:5
三、向切片中添加元素
3.1 切片中添加元素
package main
import "fmt"
func main() {
arr := make([]int, 3, 5)
arr[0] = 100 //添加100
arr[1] = 200 // 添加200
fmt.Println(arr)
}
代码输出内容:
[100 200 0]
3.2 append()函数切片添加元素
Go语言的内建函数 append() 可以为切片动态在末尾添加元素,代码如下所示:
package main
import "fmt"
func main() {
var slice []int
slice = append(slice, 1) // 追加1个元素
slice = append(slice, 2, 3, 4) // 最加多个元素
slice = append(slice, []int{5, 6, 7}...) // 追加一个切片
fmt.Println(slice)
}
代码输出内容:
[1 2 3 4 5 6 7]
注意:在使用 append() 函数为切片动态添加元素时,如果空间不足以容纳足够多的元素,切片就会进行“扩容”,此时新切片的长度会发生改变。切片在扩容时,容量的扩展规律是按容量的 2 倍数进行扩充,例如 1、2、4、8、16……,代码如下:
package main
import "fmt"
func main() {
var slice []int
for i := 0; i < 15; i++ {
slice = append(slice, i)
fmt.Printf("长度: %v 容量: %v 指针: %p\n", len(slice), cap(slice), slice)
}
}
代码执行结果:
长度: 1 容量: 1 指针: 0xc000018098
长度: 2 容量: 2 指针: 0xc0000180e0
长度: 3 容量: 4 指针: 0xc00000e1e0
长度: 4 容量: 4 指针: 0xc00000e1e0
长度: 5 容量: 8 指针: 0xc000014280
长度: 6 容量: 8 指针: 0xc000014280
长度: 7 容量: 8 指针: 0xc000014280
长度: 8 容量: 8 指针: 0xc000014280
长度: 9 容量: 16 指针: 0xc000020180
长度: 10 容量: 16 指针: 0xc000020180
长度: 11 容量: 16 指针: 0xc000020180
长度: 12 容量: 16 指针: 0xc000020180
长度: 13 容量: 16 指针: 0xc000020180
长度: 14 容量: 16 指针: 0xc000020180
长度: 15 容量: 16 指针: 0xc000020180
除了可以在切片尾部追加,也可以在切片前面添加 示例如下:
package main
import "fmt"
func main() {
var a = []int{1, 2, 3}
a = append([]int{666}, a...) // 前面添加1个元素
fmt.Println(a)
a = append([]int{777, 888, 999}, a...) // 前面添加多个元素
fmt.Println(a)
}
代码运行结果:
[666 1 2 3]
[777 888 999 666 1 2 3]
注意:在切片开头添加元素一般都会导致内存的重新分配,而且会导致已有元素全部被复制 1 次,因此,从切片的开头添加元素的性能要比从尾部追加元素的性能差很多。
3.3 copy()函数复制切片
Go语言的内置函数 copy() 可以将一个数组切片复制到另一个数组切片中,如果加入的两个数组切片不一样大,就会按照其中较小的那个数组切片的元素个数进行复制。copy() 函数的使用格式如下:
copy( destSlice, srcSlice)
- srcSlice:数据来源切片
- destSlice:复制的目标
- 目标切片必须分配过空间且足够承载复制的元素个数,并且来源和目标的类型必须一致
下面代码展示了copy()函数的过程
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 此时slice2内容为:[1 2 3]
copy(slice1, slice2) //copy slice2对应索引的内容拷贝过来还是[1 2 3]
fmt.Println(slice1)
fmt.Println(slice2)
}
代码输出内容:
[1 2 3 4 5]
[1 2 3]
下面通过代码演示对切片的引用和复制操作后对切片元素的影响:
package main
import "fmt"
func main() {
// 设置元素数量为1000
const elementCount = 1000
// 预分配足够多的元素切片
// 预分配拥有 1000 个元素的整型切片,这个切片将作为原始数据
srcData := make([]int, elementCount)
// 将切片赋值
// 将 srcData 填充 0~999 的整型值
for i := 0; i < elementCount; i++ {
srcData[i] = i
}
// 引用切片数据
// 将 refData 引用 srcData,切片不会因为等号操作进行元素的复制
refData := srcData
// 预分配足够多的元素切片
// 预分配与 srcData 等大(大小相等)、同类型的切片 copyData
copyData := make([]int, elementCount)
// 将数据复制到新的切片空间中
// 使用 copy() 函数将原始数据复制到 copyData 切片空间中
copy(copyData, srcData)
// 修改原始数据的第一个元素
// 修改原始数据的第一个元素为 999
srcData[0] = 999
// 打印引用切片的第一个元素
// 引用数据的第一个元素将会发生变化
fmt.Println(refData[0])
// 打印复制切片的第一个和最后一个元素
// 打印复制数据的首位数据,由于数据是复制的,因此不会发生变化
fmt.Println(copyData[0], copyData[elementCount-1])
// 复制原始数据从4到6(不包含)
// 将 srcData 的局部数据复制到 copyData 中
copy(copyData, srcData[4:6])
// 打印复制局部数据后的 copyData 元素
for i := 0; i < 5; i++ {
fmt.Printf("%d ", copyData[i])
}
}
四、遍历切片
和遍历数组其实是一样的
package main
import "fmt"
func main() {
arr := make([]int, 3, 5)
arr = append(arr, 200, 300)
// // 传统for循环
// for i := 0; i < len(arr); i++ {
// fmt.Println(arr[i])
// }
for _, v := range arr {
fmt.Println(v)
}
}
五、切片截取
注意:
切片截取后返回新的切片,对新切片进行修改,会影响原切片,新切片只是指向原切片,并不是给新切片开辟内存空间。
简单举个例子:
s := []int{100, 200, 300, 400, 500, 6, 77}
s1 := s[1:3:5]
- 第一个值:起始索引位置
- 第二个值:终止索引位置 终止索引位置不包括本身
- 第三个值: 计算容量大小,容量=第三个值减去第一个值
案例:
package main
import "fmt"
func main() {
s := []int{100, 200, 300, 400, 500, 6, 77}
// 第一个值:起始索引位置
// 第二个值:终止索引位置
// 第三个值: 计算容量大小,容量=第三个值减去第一个值
s1 := s[1:3:5]
s2 := s[:] // 截取所有元素
s3 := s[3:] // 从第三个开始截取直到最后,如果没有指定第三个值,则使用s切片本身容量减去第一个值
s4 := s[:2] // 从0开始截取,到索引2
fmt.Printf("s1切片内容:%v\ts1切片长度:%v\ts1切片容量:%v\n", s1, len(s1), cap(s1))
fmt.Printf("s2切片内容:%v\ts2切片长度:%v\ts2切片容量:%v\n", s2, len(s2), cap(s2))
fmt.Printf("s3切片内容:%v\ts3切片长度:%v\ts3切片容量:%v\n", s3, len(s3), cap(s3))
fmt.Printf("s4切片内容:%v\ts4切片长度:%v\ts4切片容量:%v\n", s4, len(s4), cap(s4))
}
代码输出内容:
s1切片内容:[200 300] s1切片长度:2 s1切片容量:4
s2切片内容:[100 200 300 400 500 6 77] s2切片长度:7 s2切片容量:7
s3切片内容:[400 500 6 77] s3切片长度:4 s3切片容量:4
s4切片内容:[100 200] s4切片长度:2 s4切片容量:7
六、拓展
6.1 切片作为函数参数
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3, 4, 5, 6}
PrintFunc(a)
}
func PrintFunc(num []int) {
for i := 0; i < len(num); i++ {
fmt.Println(num[i])
}
}
代码输出内容:
1
2
3
4
5
6
在函数中修改切片的值,会影响到原切片,如下案例:
package main
func main() {
a := []int{1, 2, 3, 4, 5, 6}
PrintFunc(a)
println(a[5])
}
func PrintFunc(num []int) {
num[5] = 666 // 这里对切片进行重新赋值
}
代码输出内容:
666
6.2 切片案例: 计算一组整数之和
package main
import (
"fmt"
)
func main() {
var count int
fmt.Println("请输入要求和的个数:")
fmt.Scan(&count)
s := make([]int, count)
InitData(s)
sum := SumAdd(s)
fmt.Println(sum)
}
// 初始化函数
func InitData(num []int) {
for i := 0; i < len(num); i++ {
fmt.Printf("请输入第%d个数:\n", i+1)
fmt.Scan(&num[i]) // 切片赋值操作
}
}
// 求和函数
func SumAdd(num []int) int {
var sum int
for i := 0; i < len(num); i++ {
sum += num[i]
}
return sum
}
代码输出内容:
请输入要求和的个数:
3
请输入第1个数:
100
请输入第2个数:
200
请输入第3个数:
200
500
6.3 切片案例: 输出一组整形数据中最大的值
package main
import (
"fmt"
)
func main() {
var count int
fmt.Println("请输入要求和的个数:")
fmt.Scan(&count)
s := make([]int, count)
InitData(s)
max := Max(s)
fmt.Println("最大值是:", max)
}
// 初始化函数
func InitData(num []int) {
for i := 0; i < len(num); i++ {
fmt.Printf("请输入第%d个数:\n", i+1)
fmt.Scan(&num[i]) // 切片赋值操作
}
}
// 比较
func Max(num []int) int {
var max int = num[0]
for i := 0; i < len(num); i++ {
if num[i] > max {
max = num[i]
}
}
return max
}
代码输出内容:
请输入要求和的个数:
3
请输入第1个数:
100
请输入第2个数:
200
请输入第3个数:
400
最大值是: 400
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码