《Go程序设计语言》学习笔记之map

一. 环境

  Centos8.5, go1.17.5 linux/amd64

二. 概念

1) 散列表,是一个拥有键值对元素的无序集合。在这个集合中,键是唯一的,键对应的值可以通过键来获取、更新或移除。在Go语言中,map 是散列表的引用,map 的类型是 map[k]v ,其中 k 和 v 是字典的键和值对应的数据类型。

map 中所有的键都拥有相同的类型,同时所有的值也都拥有相同的数据类型,但是键的类型和值的类型不一定相同。

2) 键的类型 k,必须是可以通过操作符 == 来进行比较的数据类型,所以 map 可以检测某一个键是否已经存在。

三. 声明/初始化

方式一. 使用 make,声明一个 map 变量 ages,此时,它会初始化为一个空 map。

  8 func main() {
9 ages := make(map[string]int)
10
11 fmt.Println(ages == nil)
12 fmt.Println(ages)
13 }

  运行结果如下,此时 ages 是一个空 map,并非零值 nil。

声明新的空 map 的另一种方式,如下

  8 func main() {
9 ages := map[string]int{}
10
11 fmt.Println(ages == nil)
12 fmt.Println(ages)
13 }

  运行结果如下

方式二. 使用 map 的字面量来新建一个带初始化键值对元素的字典。注意第11行代码,如果大括号 } 换行,则第11行后面须有逗号,否则不用加逗号。

  8 func main() {
9 ages := map[string]int{
10 "Alice": 31,
11 "Bog": 34,
12 }
13
14 fmt.Println(ages)
15 }

  运行结果如下

这个与下面等价

  8 func main() {
9 ages := make(map[string]int)
10 ages["Alice"] = 31
11 ages["Bob"] = 34
12
13 fmt.Println(ages)
14 }

  运行结果如下

四. 访问

1) 更新键对应的值

  8 func main() {
9 ages := map[string]int{
10 "Alice": 31,
11 "Bob": 34,
12 }
13
14 ages["Alice"] = 30
15
16 fmt.Printf("age: %d\n", ages["Alice"])
17 }

  运行结果如下

2) 删除指定的元素

  8 func main() {
9 ages := map[string]int{
10 "Alice": 31,
11 "Bob": 34,
12 }
13
14 delete(ages, "Alice")
15
16 fmt.Println(ages)
17 }

  运行结果如下

3) 遍历

a. 结合 range 关键字遍历

  8 func main() {
9 ages := map[string]int{
10 "Alice": 31,
11 "Bob": 34,
12 "Smith": 23,
13 }
14
15 for k, v := range ages {
16 fmt.Printf("%5s: %d\n", k, v)
17 }
18 }

  运行结果如下

b. 按照指定的顺序遍历 map 中的元素。第19行代码,只需要 ages 中所有键,忽略了循环中的第二个变量。第23行代码,按照指定的顺序将 names 中的元素进行排序,然后按照这个顺序遍历 ages 中的值。

  9 func main() {
10 ages := map[string]int{
11 "David": 18,
12 "Smith": 23,
13 "Alice": 31,
14 "Bob": 34,
15 }
16
17 names := make([]string, 0, len(ages))
18
19 for k := range ages {
20 names = append(names, k)
21 }
22
23 sort.Strings(names)
24
25 for _, name := range names {
26 fmt.Printf("%5s: %d\n", name, ages[name])
27 }
28 }

  运行结果如下

五. 零值与判断元素是否存在

1) map 的零值是 nil,即没有引用任何散列表。

  8 func main() {
9 var ages map[string]int
10
11 fmt.Println(ages)
12 fmt.Println(nil == ages)
13 fmt.Printf("len: %d\n", len(ages))
14 }

  运行结果如下

许多操作可以在安全地在 map 的零值 nil 上执行,如查找元素、删除元素、获取 map 元素的个数(len),执行 range 循环,这些和空 map 的行为一致。

但是是向零值 map 中设置元素会导致错误。所以,设置元素前,必须初始化 map。

  4 func main() {
5 var ages map[string]int
6
7 ages["Alice"] = 27
8 }

  运行结果如下

2) 判断元素是否存在

通过下标的方式访问 map 中的元素总是会有值。如果键在 map 中,你将得到键对应的值;如果键不在 map 中,你将得到 map 值类型的零值。

有时,需要知道一个元素是否在 map 中。如果元素的类型是数值类型,我们就需要分辨一个不存在的元素和恰好这个元素的值是0的情况,因为 map[k]均为0。方式如下

  8 func main() {
9 ages := make(map[string]int)
10
11 ages["Alice"] = 27
12
13 if value, ok := ages["Bog"]; !ok {
14 fmt.Println("not exist")
15 } else {
16 fmt.Printf("%d\n", value)
17 }
18 }

  如第13行代码这种方式访问 map 中的元素输出两个值,第二个值是一个布尔值,用来报告该元素是否存在。这个布尔变量一般叫作 ok,尤其是它立即用在 if 条件判断中的时候。 

  运行结果如下

六. 比较

1) 和 slice 一样,map 不可直接进行比较,唯一合法的直接比较就是和 nil 做比较。为了判断两个 map 是否拥有相同的键和值,必须要写一个循环。

2) 当遇到不可直接比较的键类型,而又需要进行比较时,可以进行自定义一种比较方法来实现。

七. 实现集合类型的功能

Go没有提供集合类型,因为键都是唯一的,可以通过 map 来实现这一功能。比如使用 map[string]bool 的方式描述一个简单的集合。

八. 注意

无法获取 map 元素的地址。

  4 func main() {
5 ages := make(map[string]int)
6
7 ages["Alice"] = 27
8
>> 9 _ := &ages["Alice"]
10 }

  运行结果如下,编译报错 “无法获取 map 元素的地址”。原因:由于 map 的增长可能会导致已有元素被重新散列到新的存储位置,这样就可能使得获取的地址无效。

《Go程序设计语言》学习笔记之map的更多相关文章

  1. C程序设计语言学习笔记

    在Windows下运行C语言程序 Windows下的编程工具使用 VC 6.0,下面讲解如何在VC 6.0下运行上节的"Hello, world"程序. 1) 新建Win32 Co ...

  2. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  3. 2017-04-21周C语言学习笔记

    C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...

  4. 2017-05-4-C语言学习笔记

    C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...

  5. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  6. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  7. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  8. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  9. Go语言学习笔记二: 变量

    Go语言学习笔记二: 变量 今天又学了一招如何查看go的版本的命令:go version.另外上一个笔记中的代码还可以使用go run hello.go来运行,只是这种方式不会生成exe文件. 定义变 ...

  10. Go语言学习笔记(1)——顺序编程

    Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...

随机推荐

  1. JS leetcode 两数之和解答思路分析

    壹 ❀ 引 在学习算法基础的同时,我还是继续捡起leetcode的算法题了,珍惜时间,算法每天进步一点点.不得不说,在了解了一些算法概念后,至少有些答案是能看懂了......(惭愧)虽然我很菜,但是多 ...

  2. S905L3A(M401A)拆解, 运行EmuELEC和Armbian

    关于S905L3A / S905L3AB S905Lx系列没有公开资料, 猜测是Amlogic用于2B的芯片型号, 最早的 S905LB 是 S905X 的马甲, 而这个 S905L3A/S905L3 ...

  3. 使用xampp安装部署mantis

    快速教程请参考: 点击打开链接   http://download.csdn.net/detail/indexman/6830003 --------------------------- Dylan ...

  4. Java I/O 教程(十 一) BufferedWriter和BufferedReader

    Java BufferedWriter 类 Java BufferedWriter class 继承了Writer类,为Writer实例提供缓冲. 提升了写字符和字符串性能. 类定义: public ...

  5. 编译静态库遇到的 LNK2019 报错

    前文提到了 CMake 学习 文末基本涵盖了我遇到的编译问题,但是在得到一个编译好的 .lib 文件后,还需要放到项目中引用成功后才算真正的完成静态库的编译 嗯,我之所以说这些是因为我在项目中链接静态 ...

  6. win32 - wsprintfW的使用

    文档:将格式化的数据写入指定的缓冲区.根据格式字符串中相应的格式说明,将转换任何参数并将其复制到输出缓冲区.该函数在其写入的字符后附加一个终止空字符,但返回值的字符计数中不包含终止空字符. 例子: # ...

  7. OsgEarth开发笔记(二):Osg3.6.3+OsgEarth3.1+vs2019x64开发环境搭建(中)

    上一篇:<OsgEarth开发笔记(一):Osg3.6.3+OsgEarth3.1+vs2019x64开发环境搭建(上)>下一篇:敬请期待-   前言  上一篇编译了osg和osgCurl ...

  8. pexpect模块(替代subprocess)

    https://blog.csdn.net/pcn01/article/details/104993742/

  9. 06、etcd 写请求执行流程

    本篇内容主要来源于自己学习的视频,如有侵权,请联系删除,谢谢. 上一节我们学习了 etcd 读请求执行流程,这一节,我们来学习 etcd 写请求执行流程. 1.etcd写请求概览 etcd 一个写请求 ...

  10. 【Azure 环境】AAD 注册应用获取AAD Group权限接口遇 403 : Attempted to perform an unauthorized operation 错误

    问题描述 通过Azure AD的注册应用获取到Token后,访问AAD Group并查看日志信息时候,遇见了 {"error":{"code":"Un ...