切片(slice)的使用和细节说明
切片的基本介绍:
- 切片的英文名字是slice,切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。
- 切片的使用和数组类似,遍历,访问切片元素,切片长度都跟数组是一样的。
- 切片的长度是可以变化的,因此切片是一个可以动态变化的数组。
- 切片定义的语法: var 切片名 []类型 比如: var a []int
func main() { //定义一个数组 var arr = [...]int{1, 2, 3, 4} //在arr数组中定义一个切片slice,从arr数组下标1开始到下标3但是不包括3。 slice := arr[1:3] fmt.Println("arr=", arr) //1,2,3,4 fmt.Println("slice=", slice) //2,3 fmt.Println("slice元素个数是:", len(slice)) //2 fmt.Println("slice的容量是:", cap(slice)) //3 切片的容量是可以动态变化的 }
切片在内存中的形式:
slice的确是一个引用类型,从底层来说,其实就是一个数据结构(struct结构体)。
type slice struct{ ptr *[2]int len int cap int }
切片的定义方式:
func main() { //方式1 从某个数组上引用 var arr = [...]int{1, 2, 3, 4} slice := arr[1:3] fmt.Println("slice=", slice) //方式2 通过make来创建切片 对于切片必须make后才可以使用 第一个参数是数据类型,第二参数是长度,第三个参数可选是容量 //容量必须大于等于长度 var slice2 []float64 = make([]float64, 5, 10) fmt.Println("slice2=", slice2) //slice2= [0 0 0 0 0] //方式3 直接指定 var slice3 = []string{"tom", "marry", "jack"} fmt.Println("slice3=", slice3) }
方式2的内存图:
- 通过make方式创建的切片可以指定切片的大小和容量。
- 如果没有给切片的各个元素赋值,那么就会使用默认值。
- 通过make方式创建的切片对应的数组是有make底层维护,对外不可见,即只能通过slice去访问各个元素。
切片的遍历:
func main() { //定义切片 var arr = [...]int{10, 20, 30, 40, 50} slice := arr[1:4] //方式1 for i := 0; i < len(slice); i++ { fmt.Printf("slice[%v]=%v ", i, slice[i]) //slice[0]=20 slice[1]=30 slice[2]=40 } fmt.Println() //换行 //方式2 for index, value := range slice { fmt.Printf("slice[%v]=%v ", index, value) } }
切片的细节说明:
- 切片初始化时 var slice = arr[startIndex : endIndex] 说明:从arr数组下标为startIndex,取到endIndex下标的元素(不包含endIndex)。
- 切片初始化时,仍不能越界,范围在[0,len(arr)]之间,但是可以动态增长。
- var slice = arr[:end] 从0-end end为指定的下标。
- var slice = arr[start:] 从start-arr的长度 start为指定的下标。
- var slice = arr[:] 取整个数组。
- cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
- 切片定义完以后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者Make一个空间供切面使用。
- 用append内置函数,可以对切片进行动态追加。
func main() { //定义切片 var slice = []int{100, 200, 300} //给切片追加元素 返回的是一个新的切片 slice2 := append(slice, 400, 500, 600) fmt.Println("slice=", slice) //slice= [100 200 300] fmt.Println("slice2=", slice2) //slice2= [100 200 300 400 500 600] //可以把slice追加给slice2 slice2 = append(slice2,slice...) fmt.Println("slice2=", slice2) //slice2= [100 200 300 400 500 600 100 200 300] }
append原理分析:
append操作的本质其实就是对数组的扩容,go底层会创建一个新的数组newArr(按照扩容后的大小),将slice原来包含的元素拷贝到新的数组newArr,然后追加新的元素到新数组中,slice重新引用到newArr,注意newArr是在底层维护的,程序员不可见。
6. 用copy内置函数可以进行切片拷贝。拷贝出来的切片和源数组的数据空间是独立的互不影响。
func main(){ //定义切片 var slice = []int{100, 200, 300} slice3 := make([]int, 10) //指定切面的长度是10 //把slice切片的元素赋值给slice3切片 copy(slice3, slice) fmt.Println("slice3=", slice3)//slice3= [100 200 300 0 0 0 0 0 0 0] }
- 切片是引用类型,所以在传递的时候,遵守引用传递机制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)