Go(四)指针和结构体数组、切片、Map

一、数组

类型 [n]T 表示拥有 n 个 T 类型的值的数组。
表达式

var a [10]int
会将变量 a 声明为拥有 10 个整数的数组。
数组的长度是其类型的一部分,因此数组不能改变大小。这看起来是个限制,不过没关系,Go 提供了更加便利的方式来使用数组(切片)。

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
func ArrayDemo()  {
//声明一个长度为2的数组
var arr [2]string
arr[0] = "Go"
arr[1] = "Language"
fmt.Println(arr) //[Go Language]
fmt.Println(arr[0],arr[1]) //Go Language

//遍历
length := len(arr) //获取长度
for i := 0; i < length; i++ {
fmt.Printf("遍历 index[%d], value = %s \n", i, arr[i])
}

//声明并赋值
arr2 := [3]int{3, 7, 8}
fmt.Println(arr2) //[3 7 8]

//遍历
for v := range arr2{
fmt.Printf("range 遍历 value = %d \n", v)
}

//声明一个不定长度的数组
arr3 := [...]int{3, 7, 8, 5, 6}
fmt.Println(arr3) //[3 7 8]
}

二、切片

数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用。
类型 []T 表示一个元素类型为 T 的切片。
切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:

a[low : high]

它会选择一个半开区间,包括第一个元素,但排除最后一个元素。
以下表达式创建了一个切片,它包含 a 中下标从 1 到 3 的元素:

a[1:4]

切片拥有 长度len容量cap。切片的长度就是它所包含的元素个数,容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。长度和容量可通过表达式 len(s)cap(s) 来获取

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
func SliceDemo()  {
fmt.Println("切片 slice ...")
//声明一个切片
arr := []int{1, 2, 3, 4, 5, 6}
fmt.Println(arr)//[1 2 3 4 5 6]

// 切片遍历
for i, v := range arr {
fmt.Printf("index = %d, value = %d\n", i, v)
}

// 切片遍历 下标或值赋予 '_' 来忽略它
for _, v := range arr {
fmt.Printf("value = %d\n", v)
}

// 获取切片
var slice []int = arr[:] //全部元素
fmt.Println(slice)//[1 2 3 4 5 6]

slice = arr[:4] // [0,4)元素
fmt.Println(slice)//[1 2 3 4]

slice = arr[3:] // [3:5] 元素
fmt.Println(slice) //[4 5 6]

slice = arr[1:4] // 索引 (1,4] 元素
fmt.Println(slice) //[2 3 4]

//声明一个slice
var slice2 []int

//像slice其添加值
for i := 0; i < 10; i++ {
printSlice(slice2)
slice2 = append(slice2, i*2);
}

//声明一个长度len为3 类型为int的 slice
slice3 := make([]int, 3)
printSlice(slice3)

//声明一个长度len为3 cap为8 类型为int的 slice
slice4 := make([]int, 3, 8)
printSlice(slice4)

//将slice copy到slice3
copy(slice3, slice)
fmt.Println(slice3)//[2 3 4]

//删除下标为2的值
slice3 = deleteElement(slice3,2)
fmt.Println(slice3)//[2 4]

//修改下标为1的值
updateElement(slice3,1, 100)
fmt.Println(slice3)//[2 100]
}

// 修改slice的值
func updateElement(s []int, index int, val int){
s[index] = val
}

//删除元素 s 要删除的原始数据 index为要删除的索引下标
func deleteElement(s []int, index int) []int {
low := index - 1
return append(s[:low],s[index:]...)
}

//注意 这个类型 []int 并不是数组 而是 切片slice
// len 长度
// cap slice的内部机制 可理解为预留长度 容量
func printSlice(s []int) {
fmt.Printf("value = %v , len = %d , cap = %d \n" , s, len(s), cap(s))
}

三、Map

映射将键映射到值,键不能为空。零值为 nil 。nil 映射既没有键,也不能添加键。make 函数会返回给定类型的映射,并将其初始化备用。
在映射 m 中插入或修改元素:

m[key] = elem

获取元素:

elem = m[key]

删除元素:

delete(m, key)

通过双赋值检测某个键是否存在:

elem, ok = m[key]

若 key 在 m 中,ok 为 true ;否则,ok 为 false。
若 key 不在映射中,那么 elem 是该映射元素类型的零值。
同样的,当从映射中读取某个不存在的键时,结果是映射的元素类型的零值。
注 :若 elem 或 ok 还未声明,你可以使用短变量声明:

elem, ok := m[key]

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
39
40
41
42
43
44
type User struct {
name string
age int
}

func MapDemo() {
//声明一个映射 键类型为string 值类型为int
var m = map[string]int{
"age": 20,
"height" : 180,
}

fmt.Println(m)//map[age:20 height:180]
fmt.Println(m["age"], m["height"], m["width"])//20 180 0

//遍历
for k,v := range m {
fmt.Printf("key = %s , val = % d \n" ,k , v)
}

m2 := map[string]User{
"A": {name:"张三", age: 20},
"B": {name:"李四", age: 80},
}
fmt.Println(m2)//map[A:{张三 20} B:{李四 80}]

//获取元素
elem := m2["A"]
fmt.Println(elem)//{张三 20}
fmt.Println(elem.age,elem.name)//20 张三

//有值才取出
if elem,ok := m2["C"]; ok {
fmt.Println(elem)
}

//修改值
m2["A"] = User{name:"王麻子",age:34}
fmt.Println(m2)//map[A:{王麻子 34} B:{李四 80}]

//删除元素
delete(m2,"A")
fmt.Println(m2)//map[B:{李四 80}]
}