容器类型

数组

数组 是一个由 固定长度 的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。

[3]int 和 [5]int 是不同的类型

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
package main

import "fmt"

func fun1() {
var a [5]int
a[1] = 2
fmt.Println(a)
}

func fun2() {
// 二维数组
var a = [5][2]int{{1, 2}, {3, 4}}
fmt.Println(a)

}

func fun3() {
// 直接在声明时对数组进行初始化
var arr1 = [5]int{15, 20, 25, 30, 35}
fmt.Println(arr1)

// 使用短声明
arr2 := [5]int{15, 20, 25, 30, 35}
fmt.Println(arr2)

// 部分初始化, 未初始化的为零值
arr3 := [5]int{15, 20} // [15 20 0 0 0]
fmt.Println(arr3)

// 可以通过指定索引,方便地对数组某几个元素赋值
arr4 := [5]int{1: 100, 4: 200}
fmt.Println(arr4) // [0 100 0 0 200]

// 直接使用 ... 让编译器为我们计算该数组的长度
arr5 := [...]int{15, 20, 25, 30, 35, 40}
fmt.Println(arr5)
}

func main() {
//fun1()
fun2()
//fun3()
}

len函数

使用内置的 len 函数将返回数组中元素的个数,即数组的长度。

1
2
arr := [...]int{1,2,3,4}
fmt.Println(len(arr)) // 数组长度是4

数组遍历

使用 for range 循环可以获取数组每个索引以及索引上对应的元素。

1
2
3
4
5
6
7
8
9
10
func showArr() {
arr := [...]int{1, 2, 3}
for index, value := range arr {
fmt.Printf("arr[%d]=%s\n", index, value)
}

for _, value := range arr {
fmt.Printf("value=%s\n", value)
}
}

数组是值类型

Go 中的数组是值类型而不是引用类型。当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本。如果对新变量进行更改,不会影响原始数组.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func arrByValue() {
arr := [...]string{"1", "02", "03"}
b := arr
b[0] = "01"
fmt.Println(arr)
fmt.Println(b)
}

/*
输出结果
[1, 02, 03]
[01, 02, 03]
*/


切片(Slice)

切片是对数组的一个连续片段的引用,所以切片是一个引用类型。切片 本身不拥有任何数据,它们只是对现有数组的引用,每个切片值都会将数组作为其底层的数据结构。slice 的语法和数组很像,只是没有固定长度而已。

切片的声明

  1. make 函数构造一个切片,格式为 make([]Type, size, cap)
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
package main

import "fmt"

// 1.最常用声明切片
func fun1() {
var arr1 []int
arr1 = append(arr1, 1)
fmt.Println(arr1)

var arr2 = []int{}
fmt.Println(arr2)
}

// 2. make创建切片
func fun2() {
arr1 := make([]int, 3, 5)
fmt.Println(arr1)
}

func main() {
//fun1()
fun2()
}

切片的长度和容量

1
2
3
s := make([]string, 3, 5)
fmt.Println(len(s)) // 3
fmt.Println(cap(s)) // 5

切片是引用类型

由于 slice 是引用类型,所以你不对它进行赋值的话,它的默认值是 nil

切片之间不能比较,因此我们不能使用 == 操作符来判断两个 slice 是否含有全部相等元素。特别注意,如果你需要测试一个 slice 是否是空的,使用 len(s) == 0 来判断,而不应该用 s == nil 来判断。

元素修改

切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中.

1
2
3
4
5
6
7
8
var arr = [...]string{"11", "22", "33"}
s := arr[:] //[0:len(arr)]
fmt.Println(arr) //[11 22 33]
fmt.Println(s) //[11 22 33]

s[0] = "aa"
fmt.Println(arr) //[aa 22 33]
fmt.Println(s) //[aa 22 33]

元素追加

当新的元素被添加到切片时,如果容量不足,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回新的引用。现在新切片的容量是旧切片的两倍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//追加切片元素
s := []string{"11"}
fmt.Println(s)
fmt.Println(cap(s)) //1

s = append(s, "22")
fmt.Println(s)
fmt.Println(cap(s))//2

s = append(s, "33", "44")
fmt.Println(s)
fmt.Println(cap(s))//4

s = append(s, []string{"55", "66"}...)
fmt.Println(s)
fmt.Println(cap(s))//8

元素删除

删除slice中间的某个元素并保存原有的元素顺序,可以通过内置的copy函数将后面的子slice向前依次移动一位完成:

1
2
3
4
5
6
7
8
9
func remove(slice []int, i int) []int {
copy(slice[i:], slice[i+1:])
return slice[:len(slice)-1]
}

func main() {
s := []int{5, 6, 7, 8, 9}
fmt.Println(remove(s, 2)) // "[5 6 8 9]"
}

如果删除元素后不用保持原来顺序的话,我们可以简单的用最后一个元素覆盖被删除的元素:

1
2
3
4
func remove(slice []int, i int) []int {
slice[i] = slice[len(slice)-1]
return slice[:len(slice)-1]
}

Map

在 Go 语言中,map 是散列表(哈希表)的引用(引用类型)。

使用 make 函数传入键和值的类型,可以创建 map 。具体语法为 make(map[KeyType]ValueType)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建一个键类型为 string 值类型为 int 名为 mp1 的 map
mp1 := make(map[string]int)
mp2 := make(map[string]string)

//用 map 字面值的语法创建 map
var mp3 map[string]string = map[string]string{
"1": "aa",
"2": "bb",
"3": "cc",
}
fmt.Println(mp3)

mp4 := map[string]string{
"aa": "11",
"bb": "22",
"cc": "33",
}
fmt.Println(mp4)

Map 操作

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
// 添加元素
// 可以使用 `map[key] = value` 向 map 添加元素。
mp1["11"] = "aa"

//更新元素
// 若 key 已存在,使用 map[key] = value 可以直接更新对应 key 的 value 值。
mp1["11"] = "AAA"

// 获取元素
fmt.Println(mp1["11"] )

// 删除元素
//使用 delete(map, key)可以删除 map 中的对应 key 键值对,如果 key 不存在,delete 函数会静默处理,不会报错。
delete(mp1, "11")

// 判断 key 是否存在
// 如果我们想知道 map 中的某个 key 是否存在,可以使用下面的语法:value, ok := map[key]
// 这个语句说明 `map` 的下标读取可以返回两个值,第一个值为当前 `key` 的 `value` 值,第二个值表示对应的 `key` 是否存在,若存在 `ok` 为 `true` ,若不存在,则 `ok` 为 `false` 。
v3, ok := mp1["22"]
fmt.Println(ok)
fmt.Println(v3)

// 遍历map
for key, value := range mp1 {
fmt.Printf("key: %s, value: %d\n", key, value)
}

// 获取长度
fmt.Println(len(mp1))