go之切片
定义
切片是由数组建立的一种方便、灵活且功能强大的包装,切片本身不拥有任何数据。他们只是对现有数组的引用。切片底层以来于数组,是对数组的引用
底层数组如果发生变化,切片也变了;切片发生变化,层数组也变化
切片定义
基于数组生成切片
1 2 3 4 5 6 7 8 9 10 11 | package main import "fmt" func main() { var a [10]int var s = a[:] fmt.Println(s) } //[0 0 0 0 0 0 0 0 0 0] |
注意点
1 2 3 4 5 6 7 8 9 10 | package main import "fmt" func main() { var a [10]int //var s = a[:] // 把数组从第0个位置切到最后一个位置,赋值给s切片 var s []int=a[:] // 中括号中只要不放任何东西就是切片,放了数字就是数组 fmt.Println(s) } |
切片定义并初始化
切片只定义不初始化,默认0值为nil
通过make初始化
1 2 3 4 5 6 7 8 9 | package main import "fmt" func main() { var s []int=make([]int,3,4) fmt.Println(s) } //[0 0 0] |
直接定义并初始化
1 2 3 4 5 6 7 8 9 | package main import "fmt" func main() { var s []int=[]int{3,4,5} fmt.Println(s) } //[3 4 5] |
切片追加元素
数组不允许追加元素,切片可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package main import "fmt" func main() { var a [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var b []int = a[7:8] //b[0]=999 //fmt.Println(a) //[1 2 3 4 5 6 7 999 9 10] //fmt.Println(b) //[999] b = append(b, 888) fmt.Println( "切片b:" , b) //切片b: [8 888] fmt.Println( "数组a:" , a) //数组a: [1 2 3 4 5 6 7 8 888 10] fmt.Println(len(b)) //切片长度是2 fmt.Println(cap(b)) //切片容量是3 b = append(b, 777) fmt.Println( "切片b:" , b) //切片b: [8 888 777] fmt.Println( "数组a:" , a) //数组a: [1 2 3 4 5 6 7 8 888 777] fmt.Println(len(b)) //切片长度是3 fmt.Println(cap(b)) //切片容量是3 //现在长度是3,容量是3,如果再追加666的话久超过了底层数组大小 //如果超过底层数组大小:1.重新申请一个底层数据,把切片的值copy过去,2.切片的容量变为原来切片容量的两倍,3.现在这个切片跟原来的数组久没有关系了 b=append(b,666) fmt.Println( "切片b:" ,b) //切片b: [8 888 777 666] fmt.Println( "数组a:" ,a) //数组a: [1 2 3 4 5 6 7 8 888 777] fmt.Println(len(b)) //切片长度是4 fmt.Println(cap(b)) //切片长度是6 //修改切片,不会影响最原来的数组 b[0]=9 a[9]=7 fmt.Println( "切片b:" ,b) //切片b: [9 888 777 666] fmt.Println( "数组a:" ,a) //数组a: [1 2 3 4 5 6 7 8 888 7] } |
make创建切片
1 2 3 4 5 6 7 8 | import "fmt" func main() { var s =make([]int,3,4) fmt.Println(s) //[0 0 0] fmt.Println(len(s)) //3 fmt.Println(cap(s)) //4 } |
切片的零值
切片的零值为:nil
1 2 3 4 5 6 7 8 9 10 11 | import "fmt" func main() { var s []int=make([]int,2,2) // 定义,有初始化 fmt.Println(s[0]) //0 if s==nil{ fmt.Println( "我是nil" ) } else { fmt.Println( "我不是nil" ) //我不是nil } } |
1 2 3 4 5 6 7 8 9 10 11 | import "fmt" func main() { var s []int // 只定义,没有初始化 fmt.Println(s) //[] if s==nil{ fmt.Println( "我是nil" ) //我是nil } else { fmt.Println( "我不是nil" ) } } |
切片的参数传递
切片是引用类型,当参数传递在函数中修改会影响原来的
go语言的参数传递都是copy传递,因为切片是个引用(地址,指针),把切片复制了一份传入了。
由于切片是引用,在函数中根据引用改了值,改了原来的底层数组,大家都会手影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package main import "fmt" func main() { var s []int=[]int{3,4,5} testS(s) fmt.Println( "调用之后:" ,s) //调用之后: [999 4 5] } func testS(s []int) { // 在函数中追加切片,一定要注意有没有超过容量,如果超过了容量,超过后再改的值,就不会影响原来的了 fmt.Println(s) //[3 4 5] s[0]=999 //[999 3 5] s=append(s,888,777) //[999 4 5 888 777] s[1]=666 //[999 666 5 888 777] fmt.Println(s) // [999 666 5 888 777] } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package main import "fmt" func main() { var s []int = make([]int, 3, 4) testS(s) fmt.Println( "调用之后:" , s) //调用之后: [999 0 0] } func testS(s []int) { // 在函数中追加切片,一定要注意有没有超过容量,如果超过了容量,超过后再改的值,就不会影响原来的了 fmt.Println(s) //[0 0 0] s[0] = 999 //[999 0 0] 会影响原来的 s = append(s, 888, 777) //[999 0 0 888 777],追加了超过了底层数组,不依赖于原来的数组了 s[1] = 666 //[999 666 0 888 777] // 不影响原来的数组了 fmt.Println(s) // [999 666 0 888 777] } |
copy切片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package main import "fmt" func main() { var a [100000]int var b =a[:3] fmt.Println(b) //[0 0 0] b[0]=999 b[2]=222 fmt.Println(b) //[999 0 222] 使用b,虽然只用3个值,但是底层数组很大,内存占用大 //把b这个切片,copy另一个新切片上 var c= make([]int,2,2) // 基于的底层数组,数组大小是3 copy(c,b) fmt.Println(c) //[999 0] } |
多维切片
每一层都要初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 | import "fmt" func main() { //var s [][]int=make([][]int,2,2) //var s [][]int //fmt.Println(s[0]) //[] //fmt.Println(s[0][0]) // 报错,第二层没有初始化 // 循环切片 两层for循环,跟数组一样 var s [][]int=[][]int{{2,3},{4,4,4,5},{6,7,8}} fmt.Println(s) //[[2 3] [4 4 4 5] [6 7 8]] fmt.Println(s[0][1]) //3 } |
切片的底层实现
切片和数组的修改都会相互影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package main import "fmt" func main() { var a [ 10 ] int = [ 10 ] int { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } var b [] int = a[:] fmt.Println( "数组a:" ,a) / / 数组a: [ 1 2 3 4 5 6 7 8 9 10 ] fmt.Println( "切片b:" ,b) / / 切片b: [ 1 2 3 4 5 6 7 8 9 10 ] a[ 0 ] = 999 fmt.Println( "数组a:" ,a) / / 数组a: [ 999 2 3 4 5 6 7 8 9 10 ] fmt.Println( "切片b:" ,b) / / 也改了,影响了 切片b: [ 999 2 3 4 5 6 7 8 9 10 ] b[ 1 ] = 888 fmt.Println( "数组a:" ,a) / / 数组a: [ 999 888 3 4 5 6 7 8 9 10 ] fmt.Println( "切片b:" ,b) / / 切片b: [ 999 888 3 4 5 6 7 8 9 10 ] } |
切片的长度和容量
切片的长度指的是目前切片多大,容量指的是切片总共能存多少
len:内置函数查看长度
cap:内置函数查看容量,只针对于切片类型
数组类型a
1 2 3 4 5 6 7 | import "fmt" func main() { var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10} fmt.Println(len(a)) //10 数组只有个长度 fmt.Println(cap(a)) //10 数组没有容量这一说,但是用的时候不报错(没有人这么用) } |
切片类型b
1 2 3 4 5 6 7 8 | import "fmt" func main() { var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10} var b []int=a[:] fmt.Println(len(b)) //10 b切片的长度是10 fmt.Println(cap(b)) //10 b切片的容量是:10 } |
1 2 3 4 5 6 7 8 9 10 11 12 | import "fmt" func main() { var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10} var b []int=a[2:4] a[0]=999 b[0]=999 fmt.Println(a) //[999 2 999 4 5 6 7 8 9 10] fmt.Println(b) //[999 4] fmt.Println(len(b)) //b切片的长度是2 fmt.Println(cap(b)) //b切片的容量是:8 指向起始位置开始到末尾 } |
1 2 3 4 5 6 7 8 | import "fmt" func main() { var a [10]int=[10]int{1,2,3,4,5,6,7,8,9,10} var b []int=a[7:8] // 第一个数组和最后一个数字都可以不写 fmt.Println(len(b)) //b切片的长度是1 fmt.Println(cap(b)) // b切片的容量是:3 指向起始位置开始到末尾 } |
切片底层基于数组,指向数组的某个位置
切片的容量是从指向位置开始到数组结尾的个数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)