Go笔记(五):Slice
切片(Slice)是对数组的拓展,在Go中数组的长度一旦定义无法被修改,切片的长度是不固定的,可以理解为切片是一个可变长度数组,是一个有相同类型元素的可变长度序列。
1、声明切片
1.1、显示声明切片
1、语法
声明切片语法如下:
var sclicename []type
2、示例代码
1 package main 2 3 import "fmt" 4 5 // 方式一:声明/定义切片 6 func defineSlice() { 7 var slice01 []string 8 var slice02 []int 9 var arr01 [3]int 10 11 fmt.Printf("slice01: %v, 长度:%v, 容量:%v\n", slice01, len(slice01), cap(slice01)) 12 fmt.Printf("slice02: %v, 长度:%v, 容量:%v\n", slice02, len(slice02), cap(slice02)) 13 fmt.Printf("arr01: %v\n, 长度:%v, 容量:%v\n", arr01, len(arr01), cap(arr01)) 14 } 15 16 func main() { 17 defineSlice() 18 }
声明的切片(slice),默认切片的长度与容量为0。定义基本类型的切片,不会用其默认值填充切片。因为切片的长度是可变的,不像数组指定了长度,可以用基本类型的默认值填充。上述示例代码执行结果如下:
1.2、make() 函数创建切片
1、语法
make()函数可以用来初始化 slice(切片)、Map。t 表示切片类型。
func make(t Type, size ...IntegerType) Type
make([]type, length)
创建容量与数组长度不同的切片:
make([]type, length, capacity)
type:切片的类型
length:数组的长度,切片的初始长度
capacity:切片的容量值
2、示例代码
make函数创建的切片可以指定切片的数组长度len与容量capacity。
当指定切片数组长度len与容量capacity为0时,与显示声明切片等价;
当指定数组长度len与容量capacity相同并且大于0时,切片等价于数组,此时切片会对基本类型的切片设置默认值;
当指定的数组长度len小于容量capacity时,基本类型切片会在数组长度部分设置基本类型的默认值。
1 package main 2 3 import "fmt" 4 5 // 方式二:通过make声明切片 6 func makeSlice() { 7 8 // 等价于 var sliceEmpty []int 9 var sliceEmpty = make([]int, 0) 10 fmt.Printf("sliceEmpty: %v, 长度:%v, 容量:%v\n", sliceEmpty, len(sliceEmpty), cap(sliceEmpty)) 11 12 // 指定长度的与容量的切片 13 var slice01 = make([]string, 2) 14 fmt.Printf("slice01: %v, 长度:%v, 容量:%v\n", slice01, len(slice01), cap(slice01)) 15 16 // 指定长度的与容量的切片 省略类型, 需要用 = 17 var slice02 = make([]int, 3) 18 fmt.Printf("slice02: 初始值:%v, 长度:%v, 容量:%v\n", slice02, len(slice02), cap(slice02)) 19 20 // 指定长度的与容量的切片 类型推导, 需要用 := 21 slice03 := make([]bool, 2) 22 fmt.Printf("slice03: 初始值:%v, 长度:%v, 容量:%v\n", slice03, len(slice03), cap(slice03)) 23 24 // 创建指定容量的切片,capacity为 容量值;length为数组长度,也是切片的初始长度 -> make([]T, length, capacity) 25 slice04 := make([]bool, 3, 4) 26 fmt.Printf("slice04: 初始值:%v, 长度:%v, 容量%v\n", slice04, len(slice04), cap(slice04)) 27 28 // 创建指定容量的切片,capacity为 容量值;length为数组长度,也是切片的初始长度 -> make([]T, length, capacity) 29 slice05 := make([]bool, 0, 5) 30 fmt.Printf("slice05: 初始值:%v, 长度:%v, 容量%v\n", slice05, len(slice05), cap(slice05)) 31 } 32 33 func main() { 34 makeSlice() 35 }
上述代码执行结果如下:
2、初始化切片
1、直接初始化
声明切片的同时,初始化切片中的元素。
package main import "fmt" // 初始化切片方式一:直接初始化 func dirctInitSlice() { var slice01 = []int{4, 5, 6} fmt.Printf("slice01: %v, 长度:%v, 容量%v\n", slice01, len(slice01), cap(slice01)) slice02 := []string{"hello", " ", "world"} fmt.Printf("slice02: %v, 长度:%v, 容量%v\n", slice02, len(slice02), cap(slice02)) } func main() { dirctInitSlice() }
执行结果如下:
2、切片表达式初始化 切片
1 package main 2 3 import "fmt" 4 5 // 初始化切片方式二:切片表达式 6 func arrInitSlice() { 7 arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8} 8 //取索引值3 -> 6, 左包含,右不包含 9 slice01 := arr[3:7] 10 fmt.Printf("slice01: %v, 长度:%v, 容量%v\n", slice01, len(slice01), cap(slice01)) 11 // 取索引值 0 -> 5 12 slice02 := arr[:6] 13 fmt.Printf("slice02: %v, 长度:%v, 容量%v\n", slice02, len(slice02), cap(slice02)) 14 // 取索引值 2 -> 7 15 slice03 := arr[2:] 16 fmt.Printf("slice03: %v, 长度:%v, 容量%v\n", slice03, len(slice03), cap(slice03)) 17 // 取出数组中的所有元素 18 slice04 := arr[:] 19 fmt.Printf("slice04: %v, 长度:%v, 容量%v\n", slice04, len(slice04), cap(slice04)) 20 } 21 22 func main() { 23 arrInitSlice() 24 }
执行结果如下:
3、访问切片
1、切片的容量与长度
从上面的示例中已经知道
切片的容量函数:cap()、切片的长度函数:len()
具体的示例代码不再展示,参考上面的示例即可。
2、空切片的判断
在Go中 nil 表示 空,相当于Java中的null。显示声明的切片,未做任何初始化操作,切片的数组长度与容量都是0,是空切片。通过make()函数创建的切片,即使数组长度与容量都是0,也不是空切片。验证代码如下:
1 package main 2 3 import "fmt" 4 5 // 空切片的判断 6 func emptySlice() { 7 var slice01 []int 8 fmt.Printf("显示声明 slice01 ==> 长度:%v,容量:%v\n", len(slice01), cap(slice01)) 9 if slice01 == nil { 10 fmt.Printf("slice01 ==> 空切片\n") 11 } 12 13 slice02 := make([]int, 0) 14 fmt.Printf("make创建 slice02 ==> 长度:%v,容量:%v\n", len(slice02), cap(slice02)) 15 if slice02 == nil { 16 fmt.Printf("slice02 ==> 空切片\n") 17 }else { 18 fmt.Printf("slice02 ==> 非空切片\n") 19 } 20 21 slice03 := make([]int, 0, 5) 22 fmt.Printf("make创建 slice03 ==> 长度:%v,容量:%v\n", len(slice03), cap(slice03)) 23 if slice03 == nil { 24 fmt.Printf("slice03 ==> 空切片\n") 25 }else { 26 fmt.Printf("slice03 ==> 非空切片\n") 27 } 28 29 slice04 := make([]int, 2, 5) 30 fmt.Printf("make创建 slice04 ==> 长度:%v,容量:%v\n", len(slice04), cap(slice04)) 31 if slice04 == nil { 32 fmt.Printf("slice04 ==> 空切片\n") 33 } else { 34 fmt.Printf("slice04 ==> 非空切片\n") 35 } 36 37 } 38 39 func main() { 40 emptySlice() 41 }
执行结果如下:
4、遍历切片
4.1、for
1 package main 2 3 import "fmt" 4 5 // 遍历切片方式一:通过切片长度访问切片元素 6 func visitSlice01() { 7 slice01 := []bool{false, true, true} 8 for i := 0; i < len(slice01); i++ { 9 if slice01[i] { 10 fmt.Println("Yes") 11 } else { 12 fmt.Println("No") 13 } 14 } 15 } 16 17 func main() { 18 visitSlice01() 19 }
执行结果如下:
4.2、for range
1 package main 2 3 import "fmt" 4 5 // 遍历切片方式二:通过for range访问切片元素 6 func visitSlice02() { 7 slice01 := []string{"zs", "ls", "ww", "hz"} 8 for i, v := range slice01 { 9 fmt.Printf("下标:i: %v, 元素值:v: %v\n", i, v) 10 } 11 fmt.Println("-----------------------------") 12 for _, v := range slice01 { 13 fmt.Printf("元素值:v: %v\n", v) 14 } 15 } 16 17 func main() { 18 visitSlice02() 19 }
执行结果如下:
5、操作切片
切片是动态的数组,可使用append()函数添加元素。
切片是引用类型,通过赋值的方式会修改原有内容,可通过copy()函数拷贝切片。
5.1、添加
1、添加元素
1 package main 2 import "fmt" 3 // 添加元素 4 func addEleSlice01() { 5 slice01 := []int{} 6 slice01 = append(slice01, 1) 7 slice01 = append(slice01, 2) 8 slice01 = append(slice01, 3) 9 slice01 = append(slice01, 4, 5, 6) 10 fmt.Printf("slice01: %v\n", slice01) 11 } 12 func main() { 13 addEleSlice01() 14 }
执行结果如下:
2、添加切片
1 package main 2 3 import "fmt" 4 5 // 添加切片 6 func addSliceToSlice() { 7 var slice01 = []string{"tom", "jack"} 8 var slice02 []string 9 slice02 = []string{"hello", "-", "world"} 10 slice03 := append(slice01, slice02...) 11 fmt.Printf("slice03: %v\n", slice03) 12 slice04 := append(slice01[:1], slice02[1:]...) 13 fmt.Printf("slice04: %v\n", slice04) 14 } 15 16 func main() { 17 addSliceToSlice() 18 }
执行结果如下:
![0](https://img2023.cnblogs.com/blog/1680081/202304/1680081-20230414084017770-628061153.png)
5.2、删除元素
Go未提供删除切片元素的方法,但可以利用切片表达式删除元素。例如:从切片slice中删除索引为index的元素,slice = append(slice[:index], slice[index+1:]...)
1 package main 2 3 import "fmt" 4 5 // 删除元素,利用切片表达式 6 func delEleSlice() { 7 slice01 := []int{1, 2, 3, 4, 5, 6} 8 // 删除索引值为3的元素 9 fmt.Printf("slice01[3]: %v\n", slice01[3]) 10 slice02 := append(slice01[:3], slice01[4:]...) 11 fmt.Printf("slice02: %v\n", slice02) 12 } 13 14 func main() { 15 delEleSlice() 16 }
执行结果如下:
![0](https://img2023.cnblogs.com/blog/1680081/202304/1680081-20230414084126324-1050307120.png)
5.3、更新元素
1 package main 2 3 import "fmt" 4 5 // 更新执行下标的切片元素 6 func updEleSlice() { 7 slice01 := []int{1, 2, 3} 8 fmt.Printf("upd before ==> slice01: %v\n", slice01) 9 slice01[1] = 200 10 fmt.Printf("upd after ==> slice01: %v\n", slice01) 11 } 12 13 func main() { 14 updEleSlice() 15 }
执行结果如下:
![0](https://img2023.cnblogs.com/blog/1680081/202304/1680081-20230414084220053-689483610.png)
6、切片的拷贝
切片是引用类型,copy()函数是一个深拷贝,切片在使用copy函数时,需要用make函数创建申请内存。
浅拷贝:将切片A的引用赋给切片B,当切片A元素值改变时,会影响切片B。
深拷贝:将切片A的元素值拷贝到切片B的内存中,当切片A元素值改变时,不会影响切片B。
1 package main 2 3 import "fmt" 4 5 // copy()函数,深拷贝 6 func copySlice() { 7 slice01 := []int{1, 2, 3} 8 // 1、浅拷贝 9 slice02 := slice01 10 // 2、深拷贝 11 // 未分配内存地址,采用此种方式声明slice03切片,copy(slice03, slice01)无效 12 var slice03 = []int{} 13 // 分配内存地址 14 slice04 := make([]int, 3) 15 copy(slice03, slice01) 16 copy(slice04, slice01) 17 18 slice01[1] = 200 19 fmt.Printf("原切片:slice01: %v\n", slice01) 20 fmt.Printf("`:=`赋值切片 :slice02: %v\n", slice02) 21 fmt.Printf("显示声明切片:slice03: %v\n", slice03) 22 fmt.Printf("make()创建指定长度与容量切片:slice04: %v\n", slice04) 23 } 24 25 func main() { 26 copySlice() 27 }
执行结果如下:
![0](https://img2023.cnblogs.com/blog/1680081/202304/1680081-20230414084336045-1562711730.png)