Slice

map 中存在 slice,slice 和 array 有点类似,但是又有区别。slice 的 api 并没有 Python 中 list那么的丰富。

切片又可以称为动态数组,切片的长度是可以改变的。切片由三个部分组成:指向底层数组的指针,切片的元素个数(长度),切片的容量。切片是引用类型。

切片指向的是底层的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import "fmt"

func main() {
// 切片的定义
var sliceVaribles []int
// 定义一个数组
arrayVariables := [...]int{12, 21, 23, 55, 98, 2}
// 切片去引用数组
sliceVaribles = arrayVariables[:]

// 获取数组元素的地址
for i := 0; i < len(arrayVariables); i++ {
fmt.Printf("数组元素:%d 的地址为:%d\n", arrayVariables[i], &arrayVariables[i])
}

// 获取切片元素的地址
for i := 0; i < len(sliceVaribles); i++ {
fmt.Printf("切片元素:%d 的地址为:%d\n", sliceVaribles[i], &sliceVaribles[i])
}
// 通过打印发现,数组元素的地址和切片元素的地址是一样的

var sliceVariables2 [] int
sliceVariables2 = arrayVariables[1:3]
fmt.Println(sliceVariables2) // [21 23]

for i := 0; i < len(sliceVariables2); i++ {
fmt.Printf("切片元素:%d 的地址为:%d\n", sliceVariables2[i], &sliceVariables2[i])
}
// [21 23] 两个切片元素的地址也是和数组中的 21 23 两个元素的地址是一样的

sliceVariables2[0] = 100
fmt.Println(arrayVariables)
fmt.Println(sliceVaribles)
fmt.Println(sliceVariables2)
// 改变切片中元素的值,那么另一个切片和数组中的值也被改变了
}

切片是动态数组

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

import "fmt"

func main() {
// 切片的定义
var sliceVariable = make([]int, 5, 6)
fmt.Printf("切片长度为:%d, 容量为:%d\n", len(sliceVariable), cap(sliceVariable))
fmt.Printf("切片底层数组地址为:%p, 切片地址为:%p\n", sliceVariable, &sliceVariable)

// 切片的追加
sliceVariable = append(sliceVariable, 0,1,2,3,4)
fmt.Printf("切片长度为:%d, 容量为:%d\n", len(sliceVariable), cap(sliceVariable))
fmt.Printf("切片底层数组地址为:%p, 切片地址为:%p\n", sliceVariable, &sliceVariable)

/**
切片长度为:5, 容量为:6
切片底层数组地址为:0xc00001e060, 切片地址为:0xc00000a060
切片长度为:10, 容量为:12
切片底层数组地址为:0xc000070060, 切片地址为:0xc00000a060

可以看出,切片的地址是不随着切片的长度发生改变的。但是切变底层的数组地址却因为长度的变化而变化。切片底层是动态数组,当容量不足时,就会发生动态的扩容操作,所以地址就会发生改变。
*/
}

创建slice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义一个空的slice
var s []int
// 动态的往里面追加值
for i:=0; i< 100;i++{
s = append(s, 2 * i * 1)
}
fmt.Println(s)

// 创建一个大小为 16 的slice
s2 := make([]int, 16)
fmt.Println(len(s2)) // 16
fmt.Println(cap(s2)) // 16
fmt.Println(s2) // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

// 创建一个大小为 16,cap 为 32 的slice
s3 := make([]int, 16, 32)
fmt.Println(len(s3)) // 16
fmt.Println(cap(s3)) // 32
fmt.Println(s3) // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

在 go 中,切片操作和 Python 的中的差不多,例如 a[2:6] 即取 a 中第2个元素到第5个元素(左闭右开) 在 go 中也同样有 [:] ,[1:],[:8] 等操作。

不同点:
Python

1
2
3
4
5
6
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = a[:6]
c = b[5:9]

print(b) # [1, 2, 3, 4, 5, 6]
print(c) # [6]

go

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

import "fmt"

func main(){
a := [...]int{1,2,3,4,5,6,7,8,9}
b := a[:6]
c := b[5:9]
fmt.Println(b) // [1 2 3 4 5 6]
fmt.Println(c) // [6 7 8 9] go 中在进行二次或者多次切片的时候,超出范围的部分,会使用原来的数组值来进行替换。
}

追加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// append
a := [...]int{1,2,3,4,5,6,7,8,9}
b := a[:8]
c := append(b, 10)
fmt.Println(cap(c)) // 9
fmt.Println(c) // [1 2 3 4 5 6 7 8 10]

fmt.Println("----------")

d := append(c, 11)
fmt.Println(cap(d)) // 18
fmt.Println(d) // [1 2 3 4 5 6 7 8 10 11]

// 添加元素时,如果超越 cap,系统会重新分配更大的底层数组
// 由于值传递的关系,必须接收 append 的返回值

copy

1
2
3
// copy
copy(s2, d)
fmt.Println(s2)

delete

1
2
3
4
// delete,go 中是没有 delete 相关的函数的,但是我们可以结合 append 和 切片来实现 delete 的功能。
fmt.Println(s2) // [1 2 3 4 5 6 7 8 10 11 0 0 0 0 0 0], 例如我们需要删除 第四个元素 4。
s2 = append(s2[:3], s2[4:]...) // append 中第二个参数为一个一个的不定参数,但是我们也可以传入一个 slice,后面跟上 ... 即可
fmt.Println(s2) // [1 2 3 5 6 7 8 10 11 0 0 0 0 0 0]

删除头元素

1
2
3
4
5
6
// 删除头元素
fmt.Println(s2) // [1 2 3 5 6 7 8 10 11 0 0 0 0 0 0]

front := s2[0]
s2 = s2[1:]
fmt.Println(front, s2) // 1 [2 3 5 6 7 8 10 11 0 0 0 0 0 0]

删除尾元素

1
2
3
4
// 删除尾元素
back := s2[len(s2)-1]
s2 = s2[:len(s2)-1]
fmt.Println(back, s2) // 0 [2 3 5 6 7 8 10 11 0 0 0 0 0]

slice 和数组的区别

https://segmentfault.com/a/1190000013148775