go20/day02/slice/main.go
yumaojun03 277c5dd15c ```
feat(slice): 添加切片详细示例和图片资源

- 在README.md中添加image-2.png、image-3.png、image-4.png图片引用,
用于说明切片操作的可视化内容
- 将"通过切片创建新的切片"章节内容重新排序至切片拷贝部分之后
- 在main.go中增加多种切片声明方式的代码示例
- 补充切片访问、遍历、引用类型特性、深拷贝等完整示例
- 添加append.drawio和ref.drawio绘图文件,提供切片操作流程图
```
2026-01-11 16:07:07 +08:00

114 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import "fmt"
func main() {
/*
声明与赋值
*/
// 1. 声明切片, 切片不是一个值是一个boxed结构体, array unsafe.Pointer // 数组指针
// 底层数组的长度: 容量10, 当前有几个元素3
// 需要考虑性能时,这个常用
slice1 := make([]int, 3, 5)
fmt.Println(slice1, len(slice1), cap(slice1))
// 底层数组的长度: 容量10, 当前有几个元素3
slice1 = append(slice1, 4, 5)
fmt.Println(slice1, len(slice1), cap(slice1))
// 这里的容器, 不是硬性限制,是超过容量后,底层数组是自动扩容的(重要)
// 扩容: 一般是原来的2倍, 新申请一块更大的数组, 把老数据copy过去
slice1 = append(slice1, 6)
fmt.Println(slice1, len(slice1), cap(slice1))
// 2. 声明并赋值 (不常用)
var slice2 []int
slice2 = []int{1, 2, 3, 4, 5}
fmt.Println(slice2, len(slice2), cap(slice2))
// 3. 声明赋值放在一起 (常用)
var slice3 []int = []int{1, 2, 3, 4, 5}
fmt.Println(slice3, len(slice3), cap(slice3))
// 4. 快捷声明赋值 (常用)
slice4 := []int{1, 2, 3, 4, 5}
fmt.Println(slice4, len(slice4), cap(slice4))
/*
切片的访问
1. 通过下标(元素的索引)访问切片元素
2. 元素值修改,直接通过下标赋值即可
*/
fmt.Println("slice4[0]=", slice4[0])
slice4[0] = 100
fmt.Println("slice4[0]=", slice4[0])
/*
切片中添加元素
append(切片变量, 元素1, 元素2, ...)
注意append 后 是参数一个新的切片变量, 所以要接收返回值
动作: 申请了新的底层数组, 把老数据copy过去 然后添加新的元素
append的元素如果超过容器会触发地址扩容, 新的数组
*/
slice4_v2 := append(slice4, 6, 7, 8)
fmt.Println("slice4:", slice4, len(slice4), cap(slice4))
fmt.Println("slice4_v2:", slice4_v2, len(slice4_v2), cap(slice4_v2))
/*
1. nil 切片: 没有分配内存(array指针是nil), 长度和容量都是0
2. 空切片
切片时一个应用类型(盒子)
*/
var slice5 []int // nil 切片
fmt.Println(slice5, len(slice5), cap(slice5))
slice5 = append(slice5, 10, 11, 12)
fmt.Println(slice5, len(slice5), cap(slice5))
slice6 := []int{} // 空切片
fmt.Println(slice6, len(slice6), cap(slice6))
slice6 = append(slice6, 10)
fmt.Println(slice6, len(slice6), cap(slice6))
/*
切片的遍历
1. for 循环遍历, 实际上遍历的也是底层的数组
2. for range 遍历
*/
fmt.Println("== 切片的遍历: for ==")
for i := 0; i < len(slice4_v2); i++ {
fmt.Printf("slice4_v2[%d]=%d\n", i, slice4_v2[i])
}
fmt.Println("== 切片的遍历: for range (推荐) ==")
for index, value := range slice4_v2 {
fmt.Printf("slice4_v2[%d]=%d\n", index, value)
}
/*
切片是一种引用类型
注意: 数组是引用类型吗? 不是
1. 如果是数组: 是2块隔离的内存地址空间(线性分配)
2. 如果是切片: 底层数组是同一块内存地址空间
浅拷贝: 赋值 底层数据没有copy一份 还是指向同一块内存地址空间
*/
fmt.Println("== 切片是一种引用类型 ==")
slice7 := []int{1, 2, 3}
slice8 := slice7
fmt.Println("slice7:", slice7)
fmt.Println("slice8:", slice8)
slice8[0] = 1000
fmt.Println("slice7:", slice7)
fmt.Println("slice8:", slice8)
/*
切片的拷贝
如果希望把 底层arry里面的数据copy到另一个切片中
使用内置函数: copy(目标切片, 源切片)
深拷贝: 底层数据已copy一份 申请一片新的内存来存储这个值
*/
fmt.Println("== 切片的拷贝 ==")
slice9 := make([]int, len(slice7))
copy(slice9, slice7)
fmt.Println("slice9:", slice9)
slice9[0] = 2000
fmt.Println("slice7:", slice7)
fmt.Println("slice9:", slice9)
}