Go的第六课——复杂数据类型的定义和使用

数组(Array)

定义

数组是相同数据类型的一组数据的集合,数组一旦定义长度不能修改,数组可以通过下标(或者叫索引)来访问元素。

定义方法:

1
var identifier [size]type

但是数组初始化又有点奇怪,并不能直接在后面等号,而是这样子去初始化

1
var identifier = [size]type{val1, val2 ...}

当然,如果少了 var 那就要把等号变为 :=。如果是初始化,那么 size 可以填 ... 来让后面给的值决定前面的 size

除此之外还可以指定下标初始化。

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
var s = [...]int{0: 1, 2: 2, 1000: 9}
fmt.Print(s[1000])
}

函数 len 可以返回一个数组的长度,目测不止,应该可以返回很多种的集合类数据的长度。

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

import "fmt"

func main() {
var s = [...]int{0: 1, 2: 2, 1000: 9}
fmt.Printf("len:%d\n", len(s))
}
/*
len:1001
*/

数组遍历

根据数组长度遍历

直接一个 for 循环

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

import "fmt"

func main() {
var s = [...]int{0: 1, 2: 2, 10: 9}
for i := 0; i < len(s); i++ {
fmt.Printf("a[%v]=%v\n", i, s[i])
}
}
/*
a[0]=1
a[1]=0
a[2]=2
a[3]=0
a[4]=0
a[5]=0
a[6]=0
a[7]=0
a[8]=0
a[9]=0
a[10]=9
*/

for range遍历

那就是用 for range 语句去遍历,就和 python 的 for 一样一样的

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

import "fmt"

func main() {
var s = [...]int{0: 1, 2: 2, 10: 9}
for i, v := range s {
fmt.Printf("a[%v]=%v\n", i, v)
}
}
/*
a[0]=1
a[1]=0
a[2]=2
a[3]=0
a[4]=0
a[5]=0
a[6]=0
a[7]=0
a[8]=0
a[9]=0
a[10]=9
*/

切片(Slice)

介绍

这是 golang 里面新出的一种数据类型,其实可以理解为可变长度的数组,因为一般的数组声明了就不能改变大小了,如果开太小不够,开大了又可能浪费内存,因此出现了这个数据类型。

1
var identifier []type

这里和数组唯一的区别就是不需要在方括号里面给上 size。

我们还可以用以下的方式声明一个初始确定长度的切片。

1
var identifier=make([]type,size)

再介绍一个函数 cap() 可以返回一个切片的容量,一般情况下,它和 len() 返回结果应当一致,但是应该也有不一样的情况,这个后面再看。

初始化

列表初始化

跟数组差不多,只不过我们不能加 size。

1
var identifier=[]int{v1,v2 ...}

数组初始化

我们可以用已有的数组来初始化。

1
2
var array type[size]
var identifier=array[:]

这里的 [:] 其实就是切片操作了,类比成 python 的列表即可。[start,end] 表示从下标 start 开始,不到下标 end,就是左边是闭区间,右边是开区间,如果有一个不填,那么默认是所有。比如 start 不填,那么就是左边所有,end 不填就是右边所有。

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

import "fmt"

func main() {
var a = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var s1 = a[:]
fmt.Println(s1)
s1 = a[1:]
fmt.Println(s1)
s1 = a[:5]
fmt.Println(s1)
s1 = a[6:9]
fmt.Println(s1)
}
/*
[1 2 3 4 5 6 7 8 9 10]
[2 3 4 5 6 7 8 9 10]
[1 2 3 4 5]
[7 8 9]
*/

使用 append 函数,第一个参数给切片对象,第二个参数给要添加的元素,返回一个新的切片。

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

import "fmt"

func main() {
var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
a = append(a, 11)
fmt.Println(a)
}
/*
[1 2 3 4 5 6 7 8 9 10 11]
*/

go里面没有提供删的方法,但是我们可以利用 append 去实现。

假如要删除索引为 index 的元素,我们其实就可以把 index 两边的元素取出来拼接。左边是 s[:index] 右边是 s[index+1:]。

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

import "fmt"

func main() {
var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
index := 5
a = append(a[:index], a[index+1:]...)
fmt.Println(a)
}
/*
[1 2 3 4 5 7 8 9 10]
*/

这里有一个写法就是切片后面加了三个点,它的意思表示把切片中的元素展开排起来当成参数。

如果有切片 a=[1,2,3,4,5] 那么我调用 func(a...) 等同于调用了 func(1,2,3,4,5)


改和查很简单,就不说了,遍历同数组。

映射(map)

简介

映射跟 python 的 dict 差不多,只不过没有 python 灵活,go 在使用 map 的时候必须声明键值的类型,不能混用。

声明方式:

1
var identifier map[key_type]value_type

或者是

1
var identifier = make(map[key_type]value_type)

但是目测第一种有点问题,第二种可以正常使用,第一种的那种声明方式没有初始化的话就不能通过下面那样访问索引的方式去修改或者是增加键值了,初始化了的话是可以的。

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

import "fmt"

func main() {
var m = make(map[string]string)
m["1"] = "123"
m["2"] = "345"
fmt.Println(m)
}
/*
map[1:123 2:345]
*/

后面看视频差不多懂了,一开始是这个 map 没有建立起来,就算定义了还是要初始化才能使用,没python那么方便随便用。

后面再初始化的话可以直接

1
identifier = make(map[key_type]value_type)

判断键是否存在

有个特殊的写法

1
value,ok:=map[key]

如果 key 存在,ok 为 true,如果 key 不存在,ok 为 false

遍历

遍历的话就是基本上只有 for range 一种方法了。

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

import "fmt"

func main() {
var m = make(map[string]string)
m["1"] = "123"
m["2"] = "345"
for k, v := range m {
fmt.Printf("m[%v]=%v\n", k, v)
}
}
/*
m[1]=123
m[2]=345
*/