ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 判断切片是否为空 要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。 ## 切片比较 切片之间是不能比较的,只能判断是否为 `nil` 值。 ```go s1 := make([]int, 5) s2 := s1 // fmt.Println(s1 == s2) // 非法操作。提示invalid operation: cannot compare s1 == s2 (slice can only be compared to nil) fmt.Println(s2 == nil) // 运行结果: // false ``` ## 切片遍历 有两个常用方式遍历 ```go s3 := []int{1, 2, 3, 4, 5} // 方式一 for i := 0; i < len(s3); i++ { fmt.Printf("s3[%d]: %#v\n", i, s3[i]) } // 方式二 for i, v := range s3 { fmt.Printf("s3[%d]: %#v\n", i, v) } ``` ## 切片的赋值拷贝 切片值拷贝,两个变量引用的底层数组是同一个。所以只要修改其中一个变量的元素。则另一个元素也跟着改变(一动则动) ```go s4 := make([]string, 5) s4[1] = "guangdong" s4[4] = "hunan" for i := 0; i < len(s4); i++ { fmt.Printf("s4[%d]: %#-12v, pointer: %p\n", i, s4[i], &s4[i]) } fmt.Printf("s4: %#v, pointer: %p\n\n", s4, s4) s5 := s4 for i := 0; i < len(s5); i++ { fmt.Printf("s5[%d]: %#-12v, pointer: %p\n", i, s5[i], &s5[i]) } fmt.Printf("s5: %#v, pointer: %p\n", s5, s5) // 运行结果: // s4[0]: "" , pointer: 0xc000076050 // s4[1]: "guangdong" , pointer: 0xc000076060 // s4[2]: "" , pointer: 0xc000076070 // s4[3]: "" , pointer: 0xc000076080 // s4[4]: "hunan" , pointer: 0xc000076090 // s4: []string{"", "guangdong", "", "", "hunan"}, pointer: 0xc000076050 // s5[0]: "" , pointer: 0xc000076050 // s5[1]: "guangdong" , pointer: 0xc000076060 // s5[2]: "" , pointer: 0xc000076070 // s5[3]: "" , pointer: 0xc000076080 // s5[4]: "hunan" , pointer: 0xc000076090 // s5: []string{"", "guangdong", "", "", "hunan"}, pointer: 0xc000076050 ``` ![](https://img.kancloud.cn/10/c9/10c99be020f5c2aff76fdba4c54eebd5_1446x994.png) ## 切片copy()函数复制 ```go s6 := make([]int, 5) s6[1] = 5 s6[3] = 2 for i := 0; i < len(s6); i++ { fmt.Printf("s6[%d]: %#-12v, pointer: %p\n", i, s6[i], &s6[i]) } fmt.Printf("s6: %#v, pointer: %p\n\n", s6, s6) s7 := make([]int, 5) copy(s7, s6) for i := 0; i < len(s7); i++ { fmt.Printf("s7[%d]: %#-12v, pointer: %p\n", i, s7[i], &s7[i]) } fmt.Printf("s7: %#v, pointer: %p\n", s7, s7) // 运行结果: // s6[0]: 0 , pointer: 0xc0000ba000 // s6[1]: 5 , pointer: 0xc0000ba008 // s6[2]: 0 , pointer: 0xc0000ba010 // s6[3]: 2 , pointer: 0xc0000ba018 // s6[4]: 0 , pointer: 0xc0000ba020 // s6: []int{0, 5, 0, 2, 0}, pointer: 0xc0000ba000 // s7[0]: 0 , pointer: 0xc0000ba030 // s7[1]: 5 , pointer: 0xc0000ba038 // s7[2]: 0 , pointer: 0xc0000ba040 // s7[3]: 2 , pointer: 0xc0000ba048 // s7[4]: 0 , pointer: 0xc0000ba050 // s7: []int{0, 5, 0, 2, 0}, pointer: 0xc0000ba030 ``` ![](https://img.kancloud.cn/9f/3f/9f3f6b36c21203b5334488f2a4a4c4b9_1412x1075.png) ## append添加元素 append内置函数将元素附加到切片的末尾。如果它有足够的容量,则重新划分目标以容纳新元素。如果没有,将分配一个新的底层数组。Append返回更新后的切片。 ```go s8 := make([]string, 5) for i := 0; i < len(s8); i++ { fmt.Printf("s8[%d]: %v, pointer: %p\n", i, s8[i], &s8[i]) } fmt.Println() s9 := s8[1:3] for i := 0; i < len(s9); i++ { fmt.Printf("s9[%d]: %v, pointer: %p\n", i, s9[i], &s9[i]) } fmt.Printf("s8:{ pointer: %p, len: %d, cap: %d, value: %#v }\n", s8, len(s8), cap(s8), s8) fmt.Printf("s9:{ pointer: %p, len: %d, cap: %d, value: %#v }\n\n", s9, len(s9), cap(s9), s9) // 添加单个元素 s9 = append(s9, "jiaxzeng") for i := 0; i < len(s9); i++ { fmt.Printf("s9[%d]: %v, pointer: %p\n", i, s9[i], &s9[i]) } fmt.Printf("s8:{ pointer: %p, len: %d, cap: %d, value: %#v }\n", s8, len(s8), cap(s8), s8) fmt.Printf("s9:{ pointer: %p, len: %d, cap: %d, value: %#v }\n\n", s9, len(s9), cap(s9), s9) // 添加多个元素 // 如果需要添加另一个切片里的数据 // 切片解压语法:切片[start:end]... s9 = append(s9, []string{"golang", "python", "shell"}...) for i := 0; i < len(s9); i++ { fmt.Printf("s9[%d]: %v, pointer: %p\n", i, s9[i], &s9[i]) } fmt.Printf("s8:{ pointer: %p, len: %d, cap: %d, value: %#v }\n", s8, len(s8), cap(s8), s8) fmt.Printf("s9:{ pointer: %p, len: %d, cap: %d, value: %#v }\n\n", s9, len(s9), cap(s9), s9) // 运行结果: // s8[0]: , pointer: 0xc000076050 // s8[1]: , pointer: 0xc000076060 // s8[2]: , pointer: 0xc000076070 // s8[3]: , pointer: 0xc000076080 // s8[4]: , pointer: 0xc000076090 // s9[0]: , pointer: 0xc000076060 // s9[1]: , pointer: 0xc000076070 // s8:{ pointer: 0xc000076050, len: 5, cap: 5, value: []string{"", "", "", "", ""} } // s9:{ pointer: 0xc000076060, len: 2, cap: 4, value: []string{"", ""} } // s9[0]: , pointer: 0xc000076060 // s9[1]: , pointer: 0xc000076070 // s9[2]: jiaxzeng, pointer: 0xc000076080 // s8:{ pointer: 0xc000076050, len: 5, cap: 5, value: []string{"", "", "", "jiaxzeng", ""} } // s9:{ pointer: 0xc000076060, len: 3, cap: 4, value: []string{"", "", "jiaxzeng"} } // s9[0]: , pointer: 0xc00010e000 // s9[1]: , pointer: 0xc00010e010 // s9[2]: jiaxzeng, pointer: 0xc00010e020 // s9[3]: golang, pointer: 0xc00010e030 // s9[4]: python, pointer: 0xc00010e040 // s9[5]: shell, pointer: 0xc00010e050 // s8:{ pointer: 0xc000076050, len: 5, cap: 5, value: []string{"", "", "", "jiaxzeng", ""} } // s9:{ pointer: 0xc00010e000, len: 6, cap: 8, value: []string{"", "", "jiaxzeng", "golang", "python", "shell"} } ``` ![](https://img.kancloud.cn/3a/5d/3a5d72461e64e6fed913797e938f0d1e_1393x1328.png) >[info] 总结: > - 当扩容底层数组容量足够时,append 添加元素是在原来的数组上操作。 > - 当扩容底层数组容量且不足且容量小于1024个元素时> - `扩容元素 + 原来长度` 小于 原来数组的两倍时,append添加元素是copy原来数组到其他内存上并且容量扩容成原来数组的两倍个元素。 - `扩容元素 + 原来长度` 大于 原来数组的两倍时,append添加元素是copy原来数组到其他内存上并且容量扩容成 `扩容元素 + 原来长度` 个元素。 > - 当扩容底层数组容量且不足且容量大于1024个元素时。append添加元素是copy原来数组到其他内存上并且容量扩容增加( 原容量*0.25 的倍数) 直至足够存下新扩容的所有元素。 ## 切片删除元素 Golang语言没有remove函数,但是可以曲线救国来实现删除动作。通过上面append函数来操作。 切片切割分成需要的元素,然后用append加起来就是返回值就是目标切片。 语法:append(切片[:删除的下标], 切片[删除的下标+2:]...) ```go s10 := []string{"golang", "python", "", "shell"} fmt.Printf("s10: %#v\n", s10) // 删除下标为2的元素 // 第一个参数是保留需要的切片。 // 第二个参数时是将后面数据变成切片,然后再切片解压 s10 = append(s10[:2], s10[3:]...) fmt.Printf("s10: %#v\n", s10) ``` ## 思考 以下几个printf输出什么结果 ```go a1 := [5]string{"golang", "python", "java"} s11 := a1[:2] s12 := a1[2:] s13 := a1[:] s14 := append(s13, []string{"c", "c++"}...) a1[1] = "shell" fmt.Printf("s11: %#v\n", s11) fmt.Printf("s12: %#v\n", s12) fmt.Printf("s13: %#v\n", s13) fmt.Printf("s14: %#v\n", s14) ```