Golang学习笔记-07Map

map是什么

Go语言中提供的映射关系容器为map,map 是一种无序的基于key-value键值对的集合,是Go中的内置类型。它将一个值与一个键关联起来,可以通过 key 来快速检索数据,key 类似于索引,指向数据的值。其内部使用散列表(hash)实现,因此,map 是无序的。

Go语言中的map是引用类型,必须初始化才能使用。

map的声明和初始化

Go语言中 map的声明语法如下:

1
2
/* 声明变量,默认 map 是 nil */
var map_variable map[keyType]valueType //KeyType:键的类型,ValueType:键对应的值的类型

map类型的变量默认初始值为nil,也就是还没有分配内存空间,需要使用make()函数来分配内存。语法为:

1
2
/* 使用 make 函数 */
map_variable = make(make(map[KeyType]ValueType, [cap]))

其中cap表示map的容量,该参数不是必须的。

也可以声明的时候直接初始化分配内存并填充键值对:

1
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }

如果不初始化 map,那么就会创建一个 nil map。nil map 是不能用来存放键值对的。

map基本使用

map中的数据都是成对出现的

我们可以通过key获取map中对应的value值。语法为:

1
map[key]

但是当key如果不存在的时候,我们会得到该value值类型的默认值,比如string类型得到空字符串,int类型得到0。但是程序不会报错。

map的基本使用示例代码如下:

1
2
3
4
5
6
scoreMap := make(map[string]int, 8) //初始化
scoreMap["张三"] = 90 //添加键值对
scoreMap["小明"] = 100
fmt.Println(scoreMap) //打印所有的键值对 map[小明:100 张三:90]
fmt.Println(scoreMap["小明"]) //取出key对应的value 100
fmt.Printf("type of a:%T\n", scoreMap) //map的数据类型 type of a:map[string]int

map也支持在声明的时候填充元素,例如:

1
2
3
4
userInfo := map[string]string{
"username": "沙河小王子",
"password": "123456",
}

判断某个键是否存在

Go语言中有个判断map中键是否存在的特殊写法,这样通过判断ok获取key对应的value更加合理,格式如下:

1
value, ok := map[key] //如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值

map的遍历

Go语言中使用for range遍历map。

1
2
3
4
5
6
7
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k, v := range scoreMap {
fmt.Println(k, v)
}

但我们只想遍历key的时候,可以按下面的写法:

1
2
3
for k := range scoreMap {
fmt.Println(k)
}

注意:遍历map时的元素顺序与添加键值对的顺序无关,因为map是基于hash表的,是无序的

按照指定顺序遍历map

正常使用for range对map进行遍历是,得到的是一个无序的结果,如果我们需要指定顺序的来遍历map,我们可以通过取出map所有的key,添加到切片slice中,对该slice进行排序,然后使用key来输出指定顺序的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
rand.Seed(time.Now().UnixNano()) //初始化随机数种子

var scoreMap = make(map[string]int, 200) //声明map

for i := 0; i < 100; i++ {
key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
value := rand.Intn(100) //生成0~99的随机整数
scoreMap[key] = value
}
//取出map中的所有key存入切片keys
var keys = make([]string, 0, 200)
for key := range scoreMap {
keys = append(keys, key)
}
//对切片进行排序
sort.Strings(keys)
//按照排序后的key遍历map
for _, key := range keys {
fmt.Println(key, scoreMap[key])
}
}

map键值对的删除

我们可以使用delete()内建函数从map中删除一组键值对,参数为 map 和其对应的 key,删除函数不返回任何值。格式如下:

1
delete(map, key)   //map:要删除键值对的map,key:要删除的键值对的键

map的长度

使用len函数可以确定map的长度。

1
len(map)  // 可以得到map的长度

map是引用类型的

与切片相似,map映射是引用类型。当将映射分配给一个新变量时,它们都指向相同的内部数据结构。因此,改变其中一个变量时,另一个变量的值也会随之改变。

示例代码:

1
2
3
4
5
6
7
8
9
personSalary := map[string]int{
"steve": 12000,
"jamie": 15000,
}
personSalary["mike"] = 9000
fmt.Println("Original person salary", personSalary) //Original person salary map[steve:12000 jamie:15000 mike:9000]
newPersonSalary := personSalary
newPersonSalary["mike"] = 18000
fmt.Println("Person salary changed", personSalary) //Person salary changed map[steve:12000 jamie:15000 mike:18000]

注意:map不能使用==操作符进行比较。==只能用来检查map是否为空。否则会报错:invalid operation: map1 == map2 (map can only be comparedto nil)

和切片相互作用

切片中的元素为map类型

1
2
3
4
5
6
7
8
9
10
11
12
13
var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println("after init")
// 对切片中的map元素进行初始化
mapSlice[0] = make(map[string]string, 10)
mapSlice[0]["name"] = "小王子"
mapSlice[0]["password"] = "123456"
mapSlice[0]["address"] = "沙河"
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}

map中值为切片类型

1
2
3
4
5
6
7
8
9
10
11
var sliceMap = make(map[string][]string, 3)
fmt.Println(sliceMap)
fmt.Println("after init")
key := "中国"
value, ok := sliceMap[key]
if !ok {
value = make([]string, 0, 2)
}
value = append(value, "北京", "上海")
sliceMap[key] = value
fmt.Println(sliceMap)
文章作者: Oxywen
文章链接: https://oxywen.cn/post/go/08/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 不闻星河须臾