6. 容器类型
6.1 数组
数组是一个固定长度的特定相同类型元素组成的序列。其元素个数可以为>=0个。
在Go语言中,由于数组长度是固定,且缺乏一定的灵活性,在Go语言一般较少使用,通常都是使用切片
6.1.1 数组定义
Go语言的数组定义如下所示:
// 方式一:在定义时即指定长度
var name [length]type
// 方式二:通过元素个数自动推断数组长度
var name = [...]type{ele1,ele2,...,elex}
语法说明如下所示:
- name: 定义数组的变量名
- length: 定义的数组元素的个数,即整个数组的长度,必须为整型
- type: 数组元素的数据类型
数组的元素可以通过下标来访问。在Go语言中,数组下标的范围为[0,length-1],示例代码如下所示:
package main
import "fmt"
func main() {
// 定义数组长度为5
var s [5]int
for i := 0; i < len(s); i++ {
fmt.Printf("数组s的第%d个元素为%v\n", i, s[i])
}
// 修改元素的值
for i := 0; i < len(s); i++ {
s[i] = i
}
fmt.Printf("数组s的值为:%+v\n", s)
// 根据数组元素自动推断长度
a := [...]int{1, 2, 3, 4, 5, 6}
fmt.Printf("数组a的长度为:%d,相应的元素为:%+v\n", len(a), a)
}
代码运行结果如下所示:
数组s的第0个元素为0
数组s的第1个元素为0
数组s的第2个元素为0
数组s的第3个元素为0
数组s的第4个元素为0
数组s的值为:[0 1 2 3 4]
数组a的长度为:6,相应的元素为:[1 2 3 4 5 6]
6.1.2 数组初始化
由于数组在定义时,Go语言会自动为数组元素设置零值,在需要修改其元素时,需要使用下标进行修改,会不太方便。因此可以在定义数组时,即为每个元素设置初始值,其语法格式如下所示:
var name = [length]type{ele1,ele2,...,elex}
var name = [...]type{ele1,ele2,...,elex}
// 在定义时,设置指定下标元素的值
var name = [...]type{index1:value1,index2:value2}
示例代码如下所示:
package main
import "fmt"
func main() {
// 定义数组时并初始化各个元素的值
var s1 = [3]int{1, 2, 3}
for i, v := range s1 {
fmt.Printf("数组s1的下标为%d,元素为:%+v\n", i, v)
}
// 定义数组并根据元素个数自动推断数组长度
var s2 = [...]int{4, 5, 6, 7}
fmt.Printf("数组s2的长度为%d,元素为:%+v\n", len(s2), s2)
// 定义数组,并设置部分元素的值
var s3 = [...]int{0: 100, 10: 500}
fmt.Printf("数组s2的长度为%d,元素为:%+v\n", len(s3), s3)
// 定义数组,并设置部分元素的值
var s4 = [8]int{0: 100, 5: 500}
fmt.Printf("数组s2的长度为%d,元素为:%+v\n", len(s4), s4)
}
运行结果如下所示:
数组s1的下标为0,元素为:1
数组s1的下标为1,元素为:2
数组s1的下标为2,元素为:3
数组s2的长度为4,元素为:[4 5 6 7]
数组s2的长度为11,元素为:[100 0 0 0 0 0 0 0 0 0 500]
数组s2的长度为8,元素为:[100 0 0 0 0 500 0 0]
根据以上代码运行结果总结如下所示:
- 在数组类型后面添加{},并根据数据类型设置元素的值,是最常用的方式
- 使用
...
设置数组长度,Go语言会根据最终的元素个数自动推测元素个数,使用这种方式,必须要在初始化时就要设置每个元素的初始值,否则编译无法通过 - 如果只是对数组中个别元素设置初始值,可以使用
下标:元素值
方式。如果数组长度未明确指定,则自动获取最大的下标做为数组的长度。
6.1.3 多维数组
多维数组是在一个数组中嵌套了多个数组,形成递进关系,语法格式如下所示:
var name [length1][length2]...[lengthx]type
相应的参数说明如下所示:
- name:多维数组的名称
- lengthx:每一维度的数组元素个数
- type:多维数组的数据类型
在日常开发中,二维和三维数组是比较常用的。通过二维数组可以实现类似于表格的功能,通过三维数组可以实现空间坐标系功能。
示例代码如下所示:
package main
import (
"fmt"
"math"
)
func main() {
var sheet = [3][2]int{{1, 2}, {3, 4}, {5, 6}}
for i, v1 := range sheet {
for j, v2 := range v1 {
fmt.Printf("多维数组,第%d行长度为:%d,元素为:%v,第%d列,元素为:%v\n", i+1, len(v1), v1, j+1, v2)
}
}
// 定义三维数组
var location = [3][3][3]int{{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {{10, 20, 30}, {40, 50, 60}, {70, 80, 90}}}
pointA := location[0][1]
pointB := location[1][0]
xDistance := math.Pow((float64(pointA[0]) - float64(pointB[0])), 2)
yDistance := math.Pow((float64(pointA[1]) - float64(pointB[1])), 2)
zDistance := math.Pow((float64(pointA[2]) - float64(pointB[2])), 2)
distance := math.Sqrt(xDistance + yDistance + zDistance)
fmt.Printf("pointA的会标为:%+v,pointB的会标为:%+v,对应的距离为:%+v\n", pointA, pointB, distance)
}
代码运行结果如下所示:
多维数组,第1行长度为:2,元素为:[1 2],第1列,元素为:1
多维数组,第1行长度为:2,元素为:[1 2],第2列,元素为:2
多维数组,第2行长度为:2,元素为:[3 4],第1列,元素为:3
多维数组,第2行长度为:2,元素为:[3 4],第2列,元素为:4
多维数组,第3行长度为:2,元素为:[5 6],第1列,元素为:5
多维数组,第3行长度为:2,元素为:[5 6],第2列,元素为:6
pointA的会标为:[4 5 6],pointB的会标为:[10 20 30],对应的距离为:28.930952282978865
6.2 切片
切片是一种特殊的数组结构,其可以实现动态数组功能,可以按需进行自动扩缩容其大小。底层仍然是以数组为基础进行创建的。
6.2.1 切片定义
语法格式如下所示:
// 定义切片不赋值
var name []type
// 定义切片并赋值
var name = []type{ele1,ele2,...,elex}
// 使用make定义
var name = make([]type,len,cap)
// 使用make定义,简写
name:=make([]type,len)
示例代码如下所示:
package main
import "fmt"
func main() {
// 方式一:定义切片但不赋值
var s1 []int
// 方式二:定义切片并赋值
var s2 = []int{1, 2, 3}
// 使用make定义
var s3 = make([]int, 3)
// 使用简写定义
s4 := make([]int, 2, 2)
s5 := []int{4, 5}
// 空切片这样赋值会报错
// s1[1] = 100
s2[1] = 200
s3[1] = 300
s4[1] = 400
s5[1] = 500
fmt.Printf("切片s1的值:%+v\n", s1)
fmt.Printf("切片s2的值:%+v\n", s2)
fmt.Printf("切片s3的值:%+v\n", s3)
fmt.Printf("切片s4的值:%+v\n", s4)
fmt.Printf("切片s5的值:%+v\n", s5)
}
代码运行结果如下所示:
切片s1的值:[]
切片s2的值:[1 200 3]
切片s3的值:[0 300 0]
切片s4的值:[0 400]
切片s5的值:[4 500]
注意事项:若定义了一个空切片,不能采用下标的方式的修改切片相应的值
6.2.2 添加元素
由于切片是动态数组,即使在定义的时候设置了切片长度,也可以向切片添加切片元素。向切片添加元素使用内置方法append
,其定义格式如下所示:
ss:=append(slice,eles)
ss:=append(slice1,slice2...)
- slice: 代表待新增元素的切片
- eles:代表新增元素的值,数据类型需要与切片数据类型相同
- ss: append方法返回的值,仍然为切片类型,若返回值与原有切片变量命名相同,则覆盖原有切片,如果不同,则为两个不同的切片
append方法也可以实现两个切片的拼接,但两个切片的数据类型需要一致
示例代码如下所示:
package main
import "fmt"
func main() {
var ss1 = []int{1, 2}
fmt.Printf("新增切片元素前值:%+v\n", ss1)
// 新增切片元素不覆盖原有切片
ss2 := append(ss1, 3)
fmt.Printf("新增切片元素后不覆盖原有切片的值:%+v\n", ss2)
// 新增切片元素覆盖原有切片
ss1 = append(ss1, 4)
fmt.Printf("新增切片元素后覆盖原有切片的值:%+v\n", ss1)
// 添加多个元素
ss1 = append(ss1, 5, 6, 7, 8, 9)
fmt.Printf("新增多个切片元素后覆盖原有切片的值:%+v\n", ss1)
// 拼接多个切片
ss3 := []string{"My", "name", "is", "Surpass"}
ss4 := []string{"I", "am", "in", "Shanghai"}
ss5 := append(ss3, ss4...)
fmt.Printf("ss3的元素:%+v\n", ss3)
fmt.Printf("ss4的元素:%+v\n", ss4)
fmt.Printf("ss5的元素:%+v\n", ss5)
}
代码运行结果如下所示:
新增切片元素前值:[1 2]
新增切片元素后不覆盖原有切片的值:[1 2 3]
新增切片元素后覆盖原有切片的值:[1 2 4]
新增多个切片元素后覆盖原有切片的值:[1 2 4 5 6 7 8 9]
ss3的元素:[My name is Surpass]
ss4的元素:[I am in Shanghai]
ss5的元素:[My name is Surpass I am in Shanghai]
6.2.3 截取元素
如果只需要切片的部分元素,则需要使用切片截取功能,截取方式通常是使用下标进行定位和截取。语法如下所示:
s:=slice(startIndex,endIndex)
- slice:待截取的切片
- startIndex,endIndex:截取切片的起始和终止索引下标
- s: 截取完成后的切片
- 若未设置startIndex,则默认从下标0开始,若未设置endIndex,则默认截取到切片最后一个元素
- 截取的规则是前包后不包,即 [startIndex,endIndex)
示例代码如下所示:
package main
import "fmt"
func main() {
ss := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
// 截取所有元素
s1 := ss[:]
fmt.Printf("s1: %+v\n", s1)
// 截取1-4元素的
s2 := ss[1:5]
fmt.Printf("s2: %+v\n", s2)
// 截取2之后的所有元素
s3 := ss[2:]
fmt.Printf("s3: %+v\n", s3)
// 截取第一个元素到第6个元素
s4 := ss[:6]
fmt.Printf("s4: %+v\n", s4)
// 起始和终止位置相同时
s5 := ss[2:2]
fmt.Printf("s5: %+v\n", s5)
// 通过切片截取完成筛选功能
s6 := append(ss[:1], ss[6:]...)
fmt.Printf("s6: %+v\n", s6)
}
代码运行结果如下所示:
s1: [1 2 3 4 5 6 7 8 9]
s2: [2 3 4 5]
s3: [3 4 5 6 7 8 9]
s4: [1 2 3 4 5 6]
s5: []
s6: [1 7 8 9]
根据以上运行结果,总结如下所示:
- 截取切片的固定元素必须设置截取的起始和终止位置,且不能出现越界的情况
- 截取切片时起始和终止位置相同时,截取的切片为空
- 截取切片在此之前的元素,可以仅设置终止位置即可,截取在此之后所有元素同理
- Go语言中,切片截取不支持负索引截取
6.2.4 切片复制
Go语言内置方法copy
可以将一个切片或数组复制到另一个切片或数组中,且需要两个切片的数据类型必须相同。如果两个切片或数组的长不同,程序按照复制的切片元素个数进行复制。语法格式如下所示:
s:=copy(slice1,slice2)
- slice1: 待复制的切片
- slice2: 被复制的切片
- s: copy的返回值,代表复制的元素数量
示例代码如下所示:
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
s3 := []int{7, 8, 9, 0}
s4 := []int{10}
// 将s2复制到s1
n1 := copy(s1, s2)
fmt.Printf("复制的元素数量:%d,复制后的切片s1值为:%+v\n", n1, s1)
fmt.Printf("切片s2:%+v\n", s2)
n2 := copy(s3, s2)
fmt.Printf("复制的元素数量:%d,复制后的切片s3值为:%+v\n", n2, s3)
n3 := copy(s4, s3)
fmt.Printf("复制的元素数量:%d,复制后的切片s4值为:%+v\n", n3, s4)
}
运行结果如下所示:
复制的元素数量:3,复制后的切片s1值为:[4 5 6]
切片s2:[4 5 6]
复制的元素数量:3,复制后的切片s3值为:[4 5 6 0]
复制的元素数量:1,复制后的切片s4值为:[4]
根据运行结果,总结如下所示:
- copy方法,第一个参数slice1的切片元素会被第二个参数slice2的切片元素覆盖
- 如果参数slice1和参数slice2的切片元素个数不同,复制过程以参数slice1的切片元素个数为主
- 如果参数slice1的切片元素个数大于参数slice2,则参数slice2的所有切片元素依次替换参数slice1的切片元素,参数slice1没有替换的切片元素则保持不变
以上总结为一句话,使用slice2的元素去替换slice1的切片元素,替换数量以slice1切片元素个数为主
6.2.5 切片长度和容量
使用make
方法定义切片时,必须设置切片的长度,但也有一个可选参数cap
,用于设置切片容量,默认情况下,切片长度和容量相等。我们先来看看切片的原始代码定义:
// src/runtime/slice.go
type slice struct {
array unsafe.Pointer
len int
cap int
}
从源码定义可以看出,切片的底层还是数组,其本质还是对底层数组的一个连续片断的引用,其内存模型示意图如下所示:
- len: 表示切片长度,指的是切片里面目前有几个元素
- cap: 表示给切片分配的内存空间可以容纳多少元素
示例代码如下所示:
s1 := []int{1, 2, 3}
fmt.Printf("切片值:%+v,切片的内存地址:%p,切片第一个元素的地址:%p\n", s1, &s1, &s1[0])
fmt.Printf("切片长度:%d,容量为:%d\n", len(s1), cap(s1))
// 运行结果
// 切片值:[1 2 3],切片的内存地址:0xc0000a4030,切片第一个元素的地址:0xc0000ae030
// 切片长度:3,容量为:3
在前面章节中,有使用append对切片进行扩容,在添加的元素超过其设置的长度后,会导致扩容。主要场景如下所示:
- 底层共用一个数组,没有超过容量时,不需要扩容
package main
import "fmt"
func main() {
s1 := make([]int, 3, 5)
fmt.Printf("s1地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s1, &s1[0], len(s1), cap(s1), s1)
// 生成一个新的切片
s2 := append(s1, 1, 2)
fmt.Printf("s1地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s1, &s1[0], len(s1), cap(s1), s1)
fmt.Printf("s2地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s2, &s2[0], len(s2), cap(s2), s2)
s3 := append(s1, -10)
fmt.Printf("s3地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s3, &s3[0], len(s3), cap(s3), s3)
}
运行结果如下所示:
s1地址:0xc000008048,底层数组首地址:0xc00000e420,切片长度:3 ,容量:5 ,切片值:[0 0 0]
s1地址:0xc000008048,底层数组首地址:0xc00000e420,切片长度:3 ,容量:5 ,切片值:[0 0 0]
s2地址:0xc000008078,底层数组首地址:0xc00000e420,切片长度:5 ,容量:5 ,切片值:[0 0 0 1 2]
s3地址:0xc0000080c0,底层数组首地址:0xc00000e420,切片长度:4 ,容量:5 ,切片值:[0 0 0 -10]
虽然使用同一个底层数组,但各自使用的片段不一样
- 底层共用一个数组,超过容量时,需要扩容
package main
import "fmt"
func main() {
s1 := make([]int, 3, 5)
fmt.Printf("s1地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s1, &s1[0], len(s1), cap(s1), s1)
s2 := append(s1, 1, 2, 3)
fmt.Printf("s2地址:%p,底层数组首地址:%p,切片长度:%-2d,容量:%-2d,切片值:%+v\n", &s2, &s2[0], len(s2), cap(s2), s2)
}
运行结果如下所示:
s1地址:0xc0000a4030,底层数组首地址:0xc0000b8030,切片长度:3 ,容量:5 ,切片值:[0 0 0]
s2地址:0xc0000a4060,底层数组首地址:0xc0000c2000,切片长度:6 ,容量:10,切片值:[0 0 0 1 2 3]
底层数组发生变化,而容量也发生了扩容
根据以上代码运行结果,可以总结规律如下所示:
- 增加元素时,当前长度+新增个数 <= cap 时,则不扩容,还是共用先前的底层数组
- 增加元素时,当前长度+新增个数 > cap 时,发生扩容,生成新的底层数组,并将旧的元素复制到新数组,再追加新的元素
扩容策略:当扩容后的cap<256时,则扩容时,容量翻倍,当cap>=256时,则newCap=newCap+newCap/4+192,即1.25倍后,再加192
在熟悉了切片的长度和容量后,我们再来看看切片的截取的注意事项,示例代码如下所示:
package main
import "fmt"
func main() {
s1 := []int{10, 20, 30, 40, 50}
fmt.Printf("切片s1内存地址:%p 底层数组首地址:%p,第2个元素地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s1, &s1[0], &s1[1], len(s1), cap(s1), s1)
// s1和s2共用底层数组
s2 := s1
fmt.Printf("切片s2内存地址:%p 底层数组首地址:%p,第2个元素地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s2, &s2[0], &s1[1], len(s2), cap(s2), s2)
// 切片截取,仍共用底层数组
s3 := s1[:]
fmt.Printf("切片s3内存地址:%p 底层数组首地址:%p,第2个元素地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s3, &s3[0], &s1[1], len(s3), cap(s3), s3)
// 截取第1个元素到末尾,共仍共用一个底层数组,首地址偏移一个地址
s4 := s1[1:]
fmt.Printf("切片s4内存地址:%p 底层数组首地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s4, &s4[0], len(s4), cap(s4), s4)
// 截取中间元素,仍共用底层元素
s5 := s1[1:4]
fmt.Printf("切片s5内存地址:%p 底层数组首地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s5, &s5[0], len(s5), cap(s5), s5)
// 截取开始到结尾的所有元素
s6 := s1[:4]
fmt.Printf("切片s6内存地址:%p 底层数组首地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s6, &s6[0], len(s6), cap(s6), s6)
// 截取空元素
s7 := s1[1:1]
fmt.Printf("切片s7内存地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s7, len(s7), cap(s7), s7)
s8 := s1[4:4]
fmt.Printf("切片s8内存地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s8, len(s8), cap(s8), s8)
s9 := s1[5:5]
fmt.Printf("切片s9内存地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s9, len(s9), cap(s9), s9)
s9 = append(s9, 60)
fmt.Printf("切片s9内存地址:%p 底层数组首地址:%p 切片长度:%d 容量: %d 切片值:%v\n", &s9, &s9[0], len(s9), cap(s9), s9)
}
运行结果如下所示:
切片s1内存地址:0xc0000a4030 底层数组首地址:0xc0000b8030,第2个元素地址:0xc0000b8038 切片长度:5 容量: 5 切片值:[10 20 30 40 50]
切片s2内存地址:0xc0000a4060 底层数组首地址:0xc0000b8030,第2个元素地址:0xc0000b8038 切片长度:5 容量: 5 切片值:[10 20 30 40 50]
切片s3内存地址:0xc0000a4090 底层数组首地址:0xc0000b8030,第2个元素地址:0xc0000b8038 切片长度:5 容量: 5 切片值:[10 20 30 40 50]
切片s4内存地址:0xc0000a40c0 底层数组首地址:0xc0000b8038 切片长度:4 容量: 4 切片值:[20 30 40 50]
切片s5内存地址:0xc0000a40f0 底层数组首地址:0xc0000b8038 切片长度:3 容量: 4 切片值:[20 30 40]
切片s6内存地址:0xc0000a4120 底层数组首地址:0xc0000b8030 切片长度:4 容量: 5 切片值:[10 20 30 40]
切片s7内存地址:0xc0000a4150 切片长度:0 容量: 4 切片值:[]
切片s8内存地址:0xc0000a4180 切片长度:0 容量: 1 切片值:[]
切片s9内存地址:0xc0000a41b0 切片长度:0 容量: 0 切片值:[]
切片s9内存地址:0xc0000a41b0 底层数组首地址:0xc0000a6158 切片长度:1 容量: 1 切片值:[60]
通过以上代码运行结果可以总结如下所示:
- startIndex默认为0,endIndex默认为切片长度
- 通过指针确定底层数组从哪里开始共享
- 长度=endIndex-startIndex
- 容量是底层数组从偏移的元素到结尾还有几个元素
以上代码运行图解如下所示:
6.3 Map
映射Map,是一种无序的键值对的集合,其主要特点如下所示:
- 长度可变
- 存储的元素是key-value,其中key是可hash值,value可变
- key无序不重复
- 不可索引,需要通过key来访问
- 不支持零值可用,即,必须使用make或*字面常量8构造
- 属于引用类型
6.3.1 Map定义
其定义语法如下所示:
// 仅定义一种约束条件,即仅定义一种类型
var name map[key]valueType
// 定义并赋值
var name = map[key]valueType{key:value}
var name =map[key]valueType{}
name[key]=value
// 使用make定义
name:=make(map[key]valueType)
示例代码如下所示:
package main
import "fmt"
func main() {
// 仅定义一种约束
var m1 map[int]string
// 定义并赋值
var m2 = map[int]string{1: "m2"}
var m3 = map[int]string{}
m3[1] = "m3"
// 使用make定义
m4 := make(map[int]string)
m4[1] = "m4"
fmt.Printf("m1:%+v\n", m1)
fmt.Printf("m2:%+v\n", m2)
fmt.Printf("m3:%+v\n", m3)
fmt.Printf("m4:%+v\n", m4)
}
代码运行结果如下所示:
m1:map[]
m2:map[1:m2]
m3:map[1:m3]
m4:map[1:m4]
6.3.2 Map 新增或修改
在Map可以添加和修改key对应的值,注意事项:
- key不存在,则创建新的key和value
- key存在,则覆盖其value值
示例代码如下所示:
package main
import "fmt"
func main() {
var m = make(map[string]string)
m["a"] = "a"
fmt.Printf("m value:%+v\n", m)
m["b"] = "b"
m["a"] = "aa"
fmt.Printf("m value:%+v\n", m)
}
运行结果如下所示:
m value:map[a:a]
m value:map[a:aa b:b]
6.3.3 Map查找
在Map里面一般使用key进行查找,注意事项如下:
- 若key存在,则返回相应的值
- 若key不存在,则返回零值,会导致无法判断key是否存在,需要解析返回值
if _,ok:=map[key];ok{
}
示意代码如下所示:
package main
import "fmt"
func main() {
personInfo := map[string]string{
"name": "Surpass",
"age": "28",
"location": "Shanghai",
}
existKey := "name"
notExistKey := "abc"
// key存在
fmt.Printf("key %s 存在,对应的值:%+v\n", existKey, personInfo[existKey])
// key不存在
fmt.Printf("key %s 不存在,对应的值:%+v\n", notExistKey, personInfo[notExistKey])
// 解析返回值,来判断key是否存在
if _, ok := personInfo[notExistKey]; !ok {
fmt.Printf("key %s 不存在\n", notExistKey)
}
if _, ok := personInfo[existKey]; ok {
fmt.Printf("key %s 存在,对应的值为:%s\n", existKey, personInfo[existKey])
}
}
运行结果如下所示:
key name 存在,对应的值:Surpass
key abc 存在,对应的值:
key abc 不存在
key name 存在,对应的值为:Surpass
6.3.4 Map 删除
删除Map中的元素,比较简单,基本格式如下所示:
delete(map,key)
- 若key存在,则删除相应的key-value对
- 若key不存在,也不会出现panic
示意代码如下所示:
package main
import "fmt"
func main() {
personInfo := map[string]string{
"name": "Surpass",
"age": "28",
"location": "Shanghai",
}
existKey := "name"
notExistKey := "abc"
delete(personInfo,existKey)
delete(personInfo,notExistKey)
fmt.Printf("删除后的map值:%+v\n", personInfo)
}
代码运行结果如下所示:
删除后的map值:map[age:28 location:Shanghai]
6.3.5 遍历
map的遍历使用for-range
,基本语法格式如下所示:
for k,v:=range map{
fmt.Println(k,v)
}
示例代码如下所示:
package main
import "fmt"
func main() {
personInfo := map[string]string{
"name": "Surpass",
"age": "28",
"location": "Shanghai",
}
for k,v:=range personInfo{
fmt.Printf("key:%s,value:%s\n",k,v)
}
}
运行结果如下所示:
key:location,value:Shanghai
key:name,value:Surpass
key:age,value:28