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. 如果是切片: 底层数组是同一块内存地址空间 */ 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一份 申请一片新的内存来存储这个值, 只copy一层, 浅拷贝 深copy 是递归copy, 需要自己实现, 依赖三方库, 非常耗性能, 一般不推荐使用, 最常见的方式是使用json序列化和反序列化来实现深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) fmt.Println("== 切片 切割(共享底层数组) ==") slice10 := []int{1, 2, 3} fmt.Println("slice10:", slice10) slice11 := slice10[1:3] fmt.Println("slice11:", slice11) slice11[0] = 200 fmt.Println("slice10:", slice10) fmt.Println("slice11:", slice11) /* 切片的删除 切片的删除是通过切片操作实现的,即使用切片语法来移除指定范围的元素。 */ fmt.Println("== 切片的删除 ==") slice12 := []int{1, 2, 3, 4, 5} fmt.Println("slice12:", slice12) // 1. 从老切片中过滤出需要的元素 // 2. 重新组合成一个新的切片 // 删除索引为2的元素 (值3) slice12 = append(slice12[:2], slice12[3:]...) fmt.Println("slice12:", slice12) /* 函数作为参数 */ fmt.Println("== 函数作为参数 ==") slice13 := []int{5, 3, 4, 1, 2} fmt.Println("排序前:", slice13) // 值传递 slice13_sorted := MySort(slice13) fmt.Println("排序后(值传递):", slice13_sorted) fmt.Println("原切片slice13:", slice13) // 引用传递 MySortV2(&slice13) fmt.Println("排序后(引用传递):", slice13) } // 冒泡排序: 值传递 // 返回一个新的切片(排序的结果) func MySort(arr []int) []int { // 冒泡排序 for i := 0; i < len(arr)-1; i++ { for j := 0; j < len(arr)-1-i; j++ { if arr[j] > arr[j+1] { // 值交换: a, b = b, a arr[j], arr[j+1] = arr[j+1], arr[j] } } } return arr } // 冒泡排序: 引用传递 // 直接修改传入的切片(在原切片上进行排序) func MySortV2(arr *[]int) { // 冒泡排序 for i := 0; i < len(*arr)-1; i++ { for j := 0; j < len(*arr)-1-i; j++ { if (*arr)[j] > (*arr)[j+1] { // 值交换: a, b = b, a (*arr)[j], (*arr)[j+1] = (*arr)[j+1], (*arr)[j] } } } }