10、切片的深入操作-GOLANG

append函数

数组中包含固定的元素,而切片只不过是指向数组的视图,这就为我们提供了更多的便利,比如为切片追加元素

太阳系中识别出了5颗矮行星,但是实际数量很可能不只5颗

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {

dwarfs := []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
fmt.Println(dwarfs)
dwarfs = append(dwarfs, "Orcus")//append是一个可变参数的函数,可以一次性向切片追加多个元素
fmt.Println(dwarfs)

}

image-20230309151126678

长度和容量

编写一个函数打印切片的长度和容量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func dump(label string, slice []string) {
fmt.Printf("%v:长度 %v,容量%v %v\n", label, len(slice), cap(slice), slice)
}

func main() {

dwarfs := []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
dump("矮行星", dwarfs)
dump("矮行星[:1]", dwarfs[:1])//取出一个长度的切片,但是容量还是5

}

image-20230309152050175

append详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

func dump(label string, slice []string) {
fmt.Printf("%v:长度 %v,容量%v %v\n", label, len(slice), cap(slice), slice)
}

func main() {

dwarfs := []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
dwarfs1 := append(dwarfs, "Orcus")
dwarfs2 := append(dwarfs1, "Salacia", "Quaoar", "Sedna")

dump("dwarfs", dwarfs)//长度为5,容量为5
dump("dwarfs1", dwarfs1)//长度为6,容量为10,这说明当编译器发现原有底层数组容量不够新切片追加时,复制到新的数组里,新数组是原有数组的两倍容量
dump("dwarfs2", dwarfs2)//新的数组容量够时直接追加即可

}

image-20230309152807408

验证当底层数组不够切片追加元素是是复制到新数组而不是追加老数组的容量(这句话就很灵性,因为我们都知道数组是固定长度的)

image-20230309153456648

三索引切分操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func dump(label string, slice []string) {
fmt.Printf("%v:长度 %v,容量%v %v\n", label, len(slice), cap(slice), slice)
}

func main() {

plants := []string{"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"}
terrestrial := plants[0:4:4] //指定长度为4,容量为4
worlds := append(terrestrial, "Ceres")
dump("plants", plants)
dump("terrestrial", terrestrial)
dump("world", worlds)
//如果给terrestrial分配空间的时候我们没有指定容量那么切片的容量就会是8,追加Ceres时也不会分配新的底层数组空间,这就回导致原有的plants切片的Jupiter被Ceres覆盖
}

image-20230309155748124

make函数对切片预分配

append函数操作时必须创建新的数组并且复制旧数组元素,有些时候我们并不需要那么大的空间,使用make进行预分配可以避免额外的内存分配以及复制操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func dump(label string, slice []string) {
fmt.Printf("%v:长度 %v,容量%v %v\n", label, len(slice), cap(slice), slice)
}

func main() {
dwarfs := make([]string, 0, 10) //长度为0,容量为10的切片
dump("dwarfs", dwarfs)
dwarfs = []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris", "Orcus"}
dump("dwarfs", dwarfs)
}

image-20230309161221128

声明可变参数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

func terraform(prefix string, worlds ...string) []string {

newWorlds := make([]string, len(worlds))
for i := range worlds {
newWorlds[i] = prefix + " " + worlds[i]
}
return newWorlds
}

func main() {
plants := []string{"Venus", "Mars", "Jupiter"}
newWorlds := terraform("New", plants...)
fmt.Println(plants)
fmt.Println(newWorlds)

}