1. golang切片
数组是固定长度,可以容纳相同数据类型的元素的集合。当长度固定时,使用还是带来一些限制,比如:我们申请的长度太大浪费内存,太小又不够用。
由于上述原因,我们有了go语言的切片,可以吧切片理解为,可变长度的数组,其实它底层就是使用数组实现的,增加了自动扩容功能。切片(Slice)是一个拥有相同类型元素的可变长度的序列。
1.1 切片语法
声明一个切片和声明一个数组类似,只要不添加长度就可以
var identifier []type
var identifier []type
切片是引用类型,可以使用make
函数来创建切片
var slice1 []type=make([]type,len)
也可以简写为
slice1 := make([]type,len)
var slice1 []type=make([]type,len)
也可以简写为
slice1 := make([]type,len)
也可以指定容量,其中capacity为可选参数。
make([]T, length, capacity)
make([]T, length, capacity)
这里len是数组的长度并且也是切片的初始长度
func sliceFuncs() {
//
var s1 []int
fmt.Printf("s1:%v\n", s1)
//分配内存
var s2 = make([]int, 2)
fmt.Printf("s2:%v\n", s2)
}
func sliceFuncs() {
//
var s1 []int
fmt.Printf("s1:%v\n", s1)
//分配内存
var s2 = make([]int, 2)
fmt.Printf("s2:%v\n", s2)
}
1.2 切片长度和容量
切片拥有自己的长度和容量,我们可以通过使用内置的len()
函数求长度,使用内置的cap()
函数求切片的容量。
func SliceCapFunc() {
var s1 = []int{1, 2, 3}
fmt.Printf("len(s1):%v\n", len(s1))
fmt.Printf("cap(s1):%v\n", cap(s1))
}
func SliceCapFunc() {
var s1 = []int{1, 2, 3}
fmt.Printf("len(s1):%v\n", len(s1))
fmt.Printf("cap(s1):%v\n", cap(s1))
}
1.3 切片初始化
切片的初始化方法很多,可以直接初始化,也可以使用数组初始化等。
直接初始化
func SliceCapFunc() {
var s1 = []int{1, 2, 3}
fmt.Printf("len(s1):%v\n", len(s1))
fmt.Printf("cap(s1):%v\n", cap(s1))
//直接初始化
println("----初始化----")
s2 := []int{1, 2, 3}
fmt.Printf("s2:%v\n", s2)
}
func SliceCapFunc() {
var s1 = []int{1, 2, 3}
fmt.Printf("len(s1):%v\n", len(s1))
fmt.Printf("cap(s1):%v\n", cap(s1))
//直接初始化
println("----初始化----")
s2 := []int{1, 2, 3}
fmt.Printf("s2:%v\n", s2)
}
使用数组方式初始化
func SliceCapFunc() {
//数组方式初始化
println("----组方式初始化----")
arr := [...]int{1, 2, 3, 4, 5, 6}
//取所有数据[:]
s3 := arr[:]
fmt.Printf("s3:%v\n", s3)
}
func SliceCapFunc() {
//数组方式初始化
println("----组方式初始化----")
arr := [...]int{1, 2, 3, 4, 5, 6}
//取所有数据[:]
s3 := arr[:]
fmt.Printf("s3:%v\n", s3)
}
1.4 使用数组的部分元素初始化(切片表达式)
切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片
。切片表达式中的low和high表示一个索引范围(左包含、右不包含)
,的到的切片长度=high-low,容量等于得到切片的底层数组的容量。
func sliceInit() {
var s1 = []int{1, 2, 3, 4, 5, 6}
s2 := s1[0:3]
fmt.Printf("s2:%v\n", s2)
s3 := s1[3:]
fmt.Printf("s3:%v\n", s3)
s4 := s1[2:5]
fmt.Printf("s4:%v\n", s4)
println("----------取所有元素------------")
s5 := s1[:]
fmt.Printf("s5:%v\n", s5)
}
func sliceInit() {
var s1 = []int{1, 2, 3, 4, 5, 6}
s2 := s1[0:3]
fmt.Printf("s2:%v\n", s2)
s3 := s1[3:]
fmt.Printf("s3:%v\n", s3)
s4 := s1[2:5]
fmt.Printf("s4:%v\n", s4)
println("----------取所有元素------------")
s5 := s1[:]
fmt.Printf("s5:%v\n", s5)
}
空切片
一个切片在未初始化之前默认为nil,长度为0,容量为0
func kongSlice(){
println("----------空切片------------")
var kong []int
fmt.Println(kong == nil)
fmt.Printf("len(kong):%v,cap(kong):%v", len(kong), cap(kong))
}
func kongSlice(){
println("----------空切片------------")
var kong []int
fmt.Println(kong == nil)
fmt.Printf("len(kong):%v,cap(kong):%v", len(kong), cap(kong))
}
2. 切片遍历
切片的遍历和数组的遍历类似,可以使用for循环索引遍历,或者for range循环
2.1 for循环索引遍历
func SliceForFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
for i := 0; i < len(s1); i++ {
fmt.Printf("s1[%d]:%v\n", i, s1[i])
}
}
func SliceForFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
for i := 0; i < len(s1); i++ {
fmt.Printf("s1[%d]:%v\n", i, s1[i])
}
}
2.2 for range循环遍历
func SliceForFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
println("----------for range------------")
for key, v := range s1 {
fmt.Printf("key[%d]:%v\n", key, v)
}
}
func SliceForFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
println("----------for range------------")
for key, v := range s1 {
fmt.Printf("key[%d]:%v\n", key, v)
}
}
3. 切片元素的添加和删除
切片是一个动态数组,可以使用append()
函数添加元素,go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。由于,切片是引用类型,通过赋值的方式,会修改原有内容,go提供了copy()
函数来拷贝切片。
3.1 添加元素
func sliceAppendFunc() {
s1 := []int{}
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3, 4, 5, 6) //添加多个元素
fmt.Printf("s1: %v\n", s1)
println("----------添加另一个切片---------")
s3 := []int{1, 2, 3}
s4 := []int{5, 6}
s4 = append(s4, s3...)
fmt.Printf("s4: %v\n", s4)
}
func sliceAppendFunc() {
s1 := []int{}
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3, 4, 5, 6) //添加多个元素
fmt.Printf("s1: %v\n", s1)
println("----------添加另一个切片---------")
s3 := []int{1, 2, 3}
s4 := []int{5, 6}
s4 = append(s4, s3...)
fmt.Printf("s4: %v\n", s4)
}
3.2 删除
func sliceDelFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
s2 = append(s2[:2], s2[3:]...)
fmt.Printf("s2: %v\n", s2)
}
func sliceDelFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
s2 = append(s2[:2], s2[3:]...)
fmt.Printf("s2: %v\n", s2)
}
公式:要从切片a中删除索引为
index
的元素,操作方法是a=append(a[:index],a[index+1]...)
3.3 更新值
重新赋值即可
func sliceUpdateFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
s2[1] = 100
fmt.Printf("s2: %v\n", s2)
}
func sliceUpdateFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
s2[1] = 100
fmt.Printf("s2: %v\n", s2)
}
3.4 查询
func sliceQueryFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
var key = 2
for i, v := range s2 {
if v == key {
fmt.Printf("i2索引值: %v\n", i)
}
}
}
func sliceQueryFunc() {
s2 := []int{1, 2, 3, 4, 5, 6}
var key = 2
for i, v := range s2 {
if v == key {
fmt.Printf("i2索引值: %v\n", i)
}
}
}
3.5 copy
func sliceCopyFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := s1
s1[0] = 100
fmt.Printf("s1: %v\n", s1)
fmt.Printf("s2: %v\n", s2)
println("----------------")
s3 := make([]int, 6)
copy(s3, s1)
s3[0] = 200
fmt.Printf("s3: %v\n", s3)
}
func sliceCopyFunc() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := s1
s1[0] = 100
fmt.Printf("s1: %v\n", s1)
fmt.Printf("s2: %v\n", s2)
println("----------------")
s3 := make([]int, 6)
copy(s3, s1)
s3[0] = 200
fmt.Printf("s3: %v\n", s3)
}
3. Array和Slice的区别
区别一:初始化方式
数组:
a := [3]int{1,2,3} //指定长度
//or
a := [...]int{1,2,3} //不指定长度
a := [3]int{1,2,3} //指定长度
//or
a := [...]int{1,2,3} //不指定长度
切片:
s := make([]int, 3) //指定长度
//or
s := []int{1,2,3} //不指定长度
s := make([]int, 3) //指定长度
//or
s := []int{1,2,3} //不指定长度
区别二:函数传递
当切片和数组作为参数在函数(func)中传递时,数组传递的是值,而切片传递的是指针。因此当传入的切片在函数中被改变时,函数外的切片也会同时改变。相同的情况,函数外的数组则不会发生任何变化