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、切片表达式初始化 切片

  切片的底层是数组,基于数组可通过切片表达式得到切片。切片表达式中low和high表示一个索引范围(左包含,右不包含),得到的切片长度=high-low,容量等于得到的切片的底层数组容量。
 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

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

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

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
 
posted @ 2023-04-14 08:44  无虑的小猪  阅读(28)  评论(0编辑  收藏  举报