Golang 入门 : 映射(map)
映射是一种数据结构,用于存储一系列无序的键值对,它基于键来存储值。映射的特点是能够基于键快速检索数据。键就像是数组的索引一样,指向与键关联的值。
与 C++、Java 等编程语言不同,在 Golang 中使用映射不需要引入任何库。因此 Golang 的映射使用起来更加方便。我们可以通过下图简要的理解一下映射中键值对的关系:
图中的每个键值对表示一种颜色的字符串名称及其对应的十六进制值,其中名称为键,十六进制数为值。
映射的实现
映射是一个数据集合,所以可以是使用类似处理数组和切片的方式来迭代映射中的元素。但映射是无序集合,所以即使以同样的顺序保存键值对,迭代映射时,元素的顺序可能会不一样。无序的原因是映射的实现使用了哈希表。
Golang 中的映射在底层是用哈希表实现的,在 /usr/local/go/src/runtime/hashmap.go 中可以查看它的实现细节。而 C++ 中的映射则是使用红黑树实现的。
创建和初始化映射
Golang 中有很多种方法可以创建并初始化映射,可以使用内置的 make 函数,也可以使用映射字面量。
使用 make 函数声明映射
// 创建一个映射,键的类型是 string,值的类型是 int
myMap := make(map[string]int)
使用字面量声明映射
// 创建一个映射,键和值的类型都是 string
// 使用两个键值对初始化映射
myMap := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
创建映射时,更常用的方法是使用映射字面量。映射的初始长度会根据初始化时指定的键值对的数量来确定。
映射的键可以是任何值
这个值的类型可以是内置的类型,也可以是结构类型,只要这个值可以使用 == 运算符做比较。切片、函数以及包含切片的结构类型,这些类型由于具有引用语义,不能作为映射的键,使用这些类型会造成编译错误:
// 使用映射字面量声明空映射
// 创建一个映射,使用字符串切片作为映射的键
myMap := map[[]string]int{}
如果你使用的 IDE 支持语法检查,就会提示这段代码有语法错误:
如果直接编译上面的代码,会得到一个编译时错误:
invalid map key type []string
虽然切片不能作为映射的键,但是却可以作为映射的值,这个在使用一个映射键对应一组数据时,会非常有用:
// 声明一个存储字符串切片的映射
// 创建一个映射,使用字符串切片作为值
myMap := map[int][]string{}
元素赋值
通过指定适当类型的键并给这个键赋一个值就完成了映射的键值对赋值:
// 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码
myColors := map[string]string{}
// 将 Red 的代码加入到映射
myColors["Red"] = "#da1337"
与切片类似,可以通过声明一个未初始化的映射来创建一个值为 nil 的映射(一般称为 nil 映射),nil 映射不能用于存储键值对:
// 通过声明映射创建一个 nil 映射
var myColors map[string]string
// 将 Red 的代码加入到映射
myColors["Red"] = "#da1337"
运行这段代码会产生一个运行时错误:
panic: assignment to entry in nil map
查找与遍历
测试键值是否存在
查找映射里是否存在某个键是映射的一个基本操作。这个操作往往需要用户写一些逻辑代码,根据逻辑代码确定是否完成了某个操作或者映射里是否缓存了某些数据。查找操作也可以用来比较两个映射,确定哪些键值对互相匹配,哪些键值对不匹配。
有两种方法可以检查键值对是否存在,第一种方式是获取键值对中的值以及一个表示这个键是否存在的布尔类型标志:
// 获取键 Blue 对应的值
value, exists := myColors["Blue"]
// 这个键存在吗?
if exists {
fmt.Println(value)
}
另一中方式是,只返回键对应的值,然后通过判断这个值是不是零值来确定键是否存在:
// 获取键 Blue 对应的值
value := myColors["Blue"]
// 这个键存在吗?
if value != "" {
fmt.Println(value)
}
显然,这种方式只能用在映射存储的值都是非零值的情况下。
注意:在 Golang 中,通过键来索引映射时,即便这个键不存在也总会返回一个值。在这种情况下,返回的是该值对应的类型的零值。
遍历映射
和遍历数组、切片一样,使用关键字 range 可以遍历映射中的所有值。但对映射来说,range 返回的不是索引和值,而是键值对:
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
myColors := map[string]string{
"AliceBlue":"#f0f8ff",
"Coral":"#ff7F50",
"DarkGray":"#a9a9a9",
"ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
执行上面的代码,输出如下:
Key: AliceBlue Value: #f0f8ff
Key: Coral Value: #ff7F50
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
删除映射中的元素
Golang 提供了一个内置的函数 delete() 用于删除集合中的元素,下面是一个简单的例子:
delete(myMap, "hello")
上面的代码将从 myMap 中删除键为 hello 的键值对。如果 hello 这个键不存在,那么这个调用将什么都不会发生,也不会有什么副作用。但是如果传入的映射的变量的值为 nil,该调用将导致程序抛出异常(panic)。
还以前面定义的 myColors 映射为例,我们用 delete() 函数删除其中的 Coral:
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
myColors := map[string]string{
"AliceBlue":"#f0f8ff",
"Coral":"#ff7F50",
"DarkGray":"#a9a9a9",
"ForestGreen": "#228b22",
}
// 删除键为Coral的键值对
delete(myColors, "Coral") // 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
执行上面的代码,发现输出的结果中已经没有 Coral 了:
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
Key: AliceBlue Value: #f0f8ff
在函数间传递映射
在函数间传递映射并不会制造出该映射的一个副本。实际上,当传递映射给一个函数,并对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改:
package main
import "fmt" func main() {
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
myColors := map[string]string{
"AliceBlue":"#f0f8ff",
"Coral":"#ff7F50",
"DarkGray":"#a9a9a9",
"ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
fmt.Println() // 调用函数来移除指定的键
removeColor(myColors, "Coral")
// 显示映射里的所有颜色
for key, value := range myColors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
} // removeColor 将指定映射里的键删除
func removeColor(colors map[string]string, key string) {
delete(colors, key)
}
运行上面的程序,输出如下结果:
Key: Coral Value: #ff7F50
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
Key: AliceBlue Value: #f0f8ff Key: AliceBlue Value: #f0f8ff
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
可以看到,在调用了 removeColor 函数后,main 函数中引用的映射中也不再有 Coral 颜色了。这个特性和切片类似,保证可以用很小的成本来复制映射。
总结
映射是 Golang 中内置的保存键值对类型数据的类型。从本文的示例中可以看出,Golang 映射实现的简单易用,并且在函数间传递时的性能很好、开销很低。
参考:
The Go Programming Language Specification
《Go 语言实战》
《Go语言编程入门与实战技巧》
Go基础系列:map类型
Golang 入门 : 映射(map)的更多相关文章
- Java中的映射Map - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的映射Map - 入门篇>,希望对大家有帮助,谢谢 简介 前面介绍了集合List,这里开始简单介绍下映射Map,相关类如下图所示 正 ...
- Java程序员的Golang入门指南(上)
Java程序员的Golang入门指南 1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如 ...
- Golang 入门 : channel(通道)
笔者在<Golang 入门 : 竞争条件>一文中介绍了 Golang 并发编程中需要面对的竞争条件.本文我们就介绍如何使用 Golang 提供的 channel(通道) 消除竞争条件. C ...
- VIM键盘映射 (Map)~转载
VIM键盘映射 (Map) 设置键盘映射 使用:map命令,可以将键盘上的某个按键与Vim的命令绑定起来.例如使用以下命令,可以通过F5键将单词用花括号括起来: :map <F5> i{e ...
- 图像映射map
<map>标签:带有可点击区域的图像映射 定义一个客户端图像映射.图像映射(image-map)指带有可点击区域的一幅图像. 效果图: 点击相应蓝色标签可进入详情页面浏览. 代码: < ...
- <顶>vim快捷键映射Map使用
问题描述: 使用vim中的快捷键映射map,可以自定义快捷键 问题解决: (1)vim模式 (2)map前缀 (3)删除映射Map (4)使用示例 (5)查看快捷键映射 命令行---:verbose ...
- java映射(map用法)
主要分两个接口:collection和Map 主要分三类:集合(set).列表(List).映射(Map)1.集合:没有重复对象,没有特定排序方式2.列表:对象按索引位置排序,可以有重复对象3.映射: ...
- Java程序员的Golang入门指南(下)
Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...
- JAVA核心技术I---JAVA基础知识(映射Map)
一:映射Map分类 二:Hashtable(同步,慢,数据量小) –K-V对,K和V都不允许为null –同步,多线程安全 –无序的 –适合小数据量 –主要方法:clear, contains/con ...
随机推荐
- fileWriter.go
package blog4go import ( "fmt" "path" "strings" ) // NewFileWriter ini ...
- 【bzoj1758】[Wc2010]重建计划
Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案, ...
- 【环套树+树形dp】Bzoj1040 [ZJOI2008] 骑士
Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火 ...
- BZOJ_3210_花神的浇花集会_切比雪夫距离
BZOJ_3210_花神的浇花集会_切比雪夫距离 Description 在花老师的指导下,每周4都有一个集会活动,俗称“浇水”活动. 具体浇水活动详情请见BZOJ3153 但这不是重点 花神出了好多 ...
- BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP
BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP 题意: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁 ...
- Python并发编程之深入理解yield from语法(八)
大家好,并发编程 进入第八篇. 直到上一篇,我们终于迎来了Python并发编程中,最高级.最重要.当然也是最难的知识点--协程. 当你看到这一篇的时候,请确保你对生成器的知识,有一定的了解.当然不了解 ...
- CentOS7 安装Redis 单机版
1,下载Redis4.0.9 进入Redis中文网的下载页面 http://www.redis.cn/download.html 2,上传压缩包到linux系统 cd /user/local/java ...
- SAP GUI个性化设置
大概从GUI730开始,GUI品牌化一直不被默认支持,在GUI设置选项里处于灰色状态,如下图: 不过用户还是可以修改注册表的方式来进行修改,让它可以设置! 首先运行Regedit,在目录:HKEY_L ...
- 并发的核心:CAS 是什么?Java8是如何优化 CAS 的?
大家可能都听说说 Java 中的并发包,如果想要读懂 Java 中的并发包,其核心就是要先读懂 CAS 机制,因为 CAS 可以说是并发包的底层实现原理. 今天就带大家读懂 CAS 是如何保证操作的原 ...
- Node中流的概念
在学习node的过程中,对于流的概念一直不是很理解,通过查阅一些资料,现在将自己对流的一些理解进行总结一下. 一.流的理解 首先我们必须知道什么是流,很多书中只是提到使用流读写文件怎么怎么方便,却不提 ...