切片
切片(slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的封装。它非常灵活,支持自动扩容。
与数组的区别:
1、定义写法类似
切片:var name []string
数组:var name [5]string
数组必须指定长度数字
2、相互转换
切片可以通过数组转换而来,转换成切片之后,就可以扩容了
package main import "fmt" func main() { var a = [5]int{1,2,3,4,5} fmt.Printf("a的类型是%T\n",a) var b = a[0:3] fmt.Printf("b的类型是%T\n",b) }
输出结果:
a的类型是[5]int b的类型是[]int
切片不能直接转换成数组
切片的构造
1、直接声明
package main import "fmt" func main() { e := []int{} fmt.Printf("%T",e) }
输出结果:
[]int
2、通过数组转换
package main import "fmt" func main() { var a = [5]int{1,2,3,4,5} fmt.Printf("a的类型是%T\n",a) var b = a[0:3] fmt.Printf("b的类型是%T\n",b) }
输出结果:
a的类型是[5]int b的类型是[]int
上面说了,切片的本质是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)
package main import "fmt" func main() { a := []int{1,2,3,4,5,6,7,8} s1 :=a[0:5] fmt.Printf("s1的长度是%v\n",len(s1)) fmt.Printf("s1的容量是%v\n",cap(s1)) s2 := a[3:6] fmt.Printf("s2的长度是%v\n",len(s2)) fmt.Printf("s2的容量是%v\n",cap(s2)) }
输入结果:
s1的长度是5 s1的容量是8 s2的长度是3 s2的容量是5
这个结果是正确的,看下图:
主要说下容量,容量的意思是当长度大于容量,将会报错,并长度最大就是容量的大小
3、通过make
函数构造
package main import "fmt" func main() { d := make([]int,5,10) fmt.Println(d) fmt.Printf("d的类型是%T\n",d) }
输出结果:
[0 0 0 0 0] d的类型是[]int
切片的类型
nil切片:var a []int
,这种写法是没有初始化的,未声明内存,不能直接使用
普通切片:var a []int{}
这种写法后面带{}
,代表初始化切片,申请内存
只要申请了内存的切片就不是nil
package main import "fmt" func main() { var a []int var b = []int{} fmt.Printf("a的类型是%T,b的类型是%T\n",a,b) fmt.Printf("a的值是%v,b的值是%v\n",a,b) if a == nil{ fmt.Println("a是nil") } if b == nil { fmt.Println("b是一个nil") } }
输出结果:
a的类型是[]int,b的类型是[]int a的值是[],b的值是[] a是nil
从上面结果看出,值都hi是一样的,但是只有a
是nil
再说一遍,只要申请了内存就不是nil
切片的拷贝
1、共用底层内存数据
a := make([]int,3) //使用make定义一个切片类型 b := a //声明b==a b[0] = 100 //赋值切片b第一个元素值为100 fmt.Println(a) fmt.Println(b)
输出结果:
[100 0 0] [100 0 0]
换一种写法
package main import "fmt" func main() { //var a =make([]int,5) var a = []int{1,2,3,4,5} b :=a b[1] =100 fmt.Println(a) fmt.Println(b) }
输出结果:
[1 100 3 4 5] [1 100 3 4 5]
下面拷贝完成后,会生成两个内存位置,不是共享
//切片的拷贝,拷贝完成后,会生成两个内存位置,不是共享 j :=[]int{1,2,3,4,5} k :=make([]int,5,5) copy(k,j) k[0] = 100 fmt.Println(j,k) /* 输出结果:[1 2 3 4 5] [100 2 3 4 5] */
切片的遍历
//切片的遍历,与数组一样 c := []int{1,3,5,7} for index,value := range c{ fmt.Println(index,value) }
输出结果:
0 1 1 3 2 5 3 7
切片的追加
//切片的追加 f :=[]int{1,2,3} g :=[]int{4,5,6} h :=append(f,g...) //使用append参数可解决这个问题,第二个切片后面需要加... fmt.Println(f,g,h) /* 输出结果: [1 2 3] [4 5 6] [1 2 3 4 5 6] */
切片的删除
也是append参数,把不要的信息不添加到组合中即可
//切片的删除,比如现在要删除一个切片的数据 i := []string{"北京","上海","广州","深圳"} i =append(i[0:2],i[3:]...) //从北京到上海组合起来,再从深圳到最后组合起来 fmt.Println(i) 输出结果: [北京 上海 深圳] //间接的删除了广州