Golang学习笔记_11——指针
Golang学习笔记_12——结构体
Golang学习笔记_13——数组
文章目录
- 切片
- 1. 定义
- 2. 创建
- 3. 基本操作
- 4. 动态性
- 5. 子切片
- 6. 数组和切片
- 7. 注意
- 8. 高级用法
- 源码
切片
Go语言中的切片(slice)是一种非常强大且灵活的数据结构,它基于数组,但提供了更加动态和方便的接口。
1. 定义
切片是对数组的抽象和封装,它包含三个关键部分:
- 指向数组的指针:切片存储了数组的首地址,指向数组中的某个元素。
- 切片的长度(len):切片中元素的数量。
- 切片的容量(cap):从切片的首元素到数组末尾的元素数量,表示在不需要重新分配底层数组的情况下,切片可以增长的最大长度。
2. 创建
func sliceDemo1() {// 通过字面量创建s1 := []int{1, 2, 3}// 通过make函数创建// 创建一个长度为3,容量为5的切片s2 := make([]int, 3, 5)// 基于数组创建arr := [5]int{1, 2, 3, 4, 5}s3 := arr[1:4]fmt.Println(s1, s2, s3)}
3. 基本操作
func sliceDemo2() {// 访问和修改元素s1 := []int{1, 2, 3}fmt.Println(s1[0]) // 输出1s1[0] = 10fmt.Println(s1)// 切片多重赋值a, b, c := s1[0], s1[1], s1[2]fmt.Println(a, b, c)// 切片的长度和容量s := []int{1, 2, 3, 4, 5}fmt.Println(len(s)) // 输出5fmt.Println(cap(s)) // 输出5,因为是基于字面量创建的,默认容量等于长度}
测试方法
func Test_sliceDemo2(t *testing.T) {sliceDemo2()
}
输出结果
=== RUN Test_sliceDemo2
1
[10 2 3]
10 2 3
5
5
--- PASS: Test_sliceDemo2 (0.00s)
PASS
4. 动态性
func sliceDemo3() {s := []int{1, 2, 3}s = append(s, 4, 5) // s现在是[1, 2, 3, 4, 5]fmt.Println(s)
}
测试方法
func Test_sliceDemo3(t *testing.T) {sliceDemo3()
}
输出结果
=== RUN Test_sliceDemo3
[1 2 3 4 5]
--- PASS: Test_sliceDemo3 (0.00s)
PASS
当向切片中追加元素时,如果切片的容量不足,Go会自动分配一个更大的底层数组,并将原有元素复制到新的数组中。新数组的容量通常是原容量的两倍。
5. 子切片
func sliceDemo4() {s := []int{1, 2, 3, 4, 5}subSlice := s[1:4] // subSlice是[2, 3, 4]fmt.Println(subSlice)
}
测试方法
func Test_sliceDemo4(t *testing.T) {sliceDemo4()
}
输出结果
=== RUN Test_sliceDemo4
[2 3 4]
--- PASS: Test_sliceDemo4 (0.00s)
PASS
6. 数组和切片
- 长度:数组的长度是固定的,而切片的长度是动态的。
- 内存分配:数组直接存储数据,切片是对数组的抽象,存储的是指向数组的指针、长度和容量。
- 效率:数组在栈上分配内存,效率较高,但长度固定;切片在堆上分配内存,且可以动态扩展,但有一定性能开销。
7. 注意
-
共享底层数组:多个切片可以共享同一个底层数组,修改一个切片可能影响其他切片。
-
越界访问:访问切片时,如果索引超出范围,会导致运行时错误(panic)。
-
nil切片:未初始化的切片值为
nil
,长度为0,容量为0。 -
在进行切片时,你可以利用它的默认行为来忽略上下界。切片下界的默认值为 0,上界则是该切片的长度。
var a [10]inta[0:10] a[:10] a[0:] a[:] // 上述表达是等价的
8. 高级用法
func sliceDemo5() {// 切片拷贝s := []int{1, 2, 3}var s_dst = make([]int, len(s))copy(s, s_dst)fmt.Println(s_dst)// 切片分割s1 := []int{1, 2, 3}s2 := []int{4, 5, 6}s3 := append(s1, s2...) // s3是[1, 2, 3, 4, 5, 6]fmt.Println(s3)
}
测试方法
func Test_sliceDemo5(t *testing.T) {sliceDemo5()
}
输出结果
=== RUN Test_sliceDemo5
[0 0 0]
[1 2 3 4 5 6]
--- PASS: Test_sliceDemo5 (0.00s)
PASS
源码
// slice_demo.go 文件
package _4_slice_demoimport "fmt"func sliceDemo1() {// 通过字面量创建s1 := []int{1, 2, 3}// 通过make函数创建// 创建一个长度为3,容量为5的切片s2 := make([]int, 3, 5)// 基于数组创建arr := [5]int{1, 2, 3, 4, 5}s3 := arr[1:4]fmt.Println(s1, s2, s3)}func sliceDemo2() {// 访问和修改元素s1 := []int{1, 2, 3}fmt.Println(s1[0]) // 输出1s1[0] = 10fmt.Println(s1)// 切片多重赋值a, b, c := s1[0], s1[1], s1[2]fmt.Println(a, b, c)// 切片的长度和容量s := []int{1, 2, 3, 4, 5}fmt.Println(len(s)) // 输出5fmt.Println(cap(s)) // 输出5,因为是基于字面量创建的,默认容量等于长度}func sliceDemo3() {s := []int{1, 2, 3}s = append(s, 4, 5) // s现在是[1, 2, 3, 4, 5]fmt.Println(s)
}func sliceDemo4() {s := []int{1, 2, 3, 4, 5}subSlice := s[1:4] // subSlice是[2, 3, 4]fmt.Println(subSlice)
}func sliceDemo5() {// 切片拷贝s := []int{1, 2, 3}var s_dst = make([]int, len(s))copy(s, s_dst)fmt.Println(s_dst)// 切片分割s1 := []int{1, 2, 3}s2 := []int{4, 5, 6}s3 := append(s1, s2...) // s3是[1, 2, 3, 4, 5, 6]fmt.Println(s3)
}
// 14_slice_demo_test.go 文件
package _4_slice_demoimport "testing"func Test_sliceDemo2(t *testing.T) {sliceDemo2()
}func Test_sliceDemo3(t *testing.T) {sliceDemo3()
}func Test_sliceDemo4(t *testing.T) {sliceDemo4()
}func Test_sliceDemo5(t *testing.T) {sliceDemo5()
}