字典(Map):map[K]T

K:为键类型,T:为元素(值)类型。
例:map[int] string 一个键类型为int,值类型为string的字典类型

Go语言的字典类型(map)实际上是一个哈希表(hash table)的特定实现,但是字典类型的数据类型是受限的,而哈希表是可以任意类型。
键和元素的这种对应关系叫做“映射”,键就是一个索引,我们通过在哈希表中查找键从而获得与它对应的那个元素。

哈希表的查找过程:

首先需要先把键名作为参数,传给哈希表,哈希表会用哈希函数(hash function)把键值转换为哈希值。

哈希值是一个无符号的整数,哈希表先用这个键的哈希值的低几位去定位到一个哈希桶(bucket,均匀地存储所属哈希表中的键-元素对),

然后再去这个哈希桶中查找这个键,而一旦找到了这个键,就能找到对应的元素值。

随后,哈希表就会把元素值作为结果返回。

综上所述,映射过程的第一步就是把键值转换为哈希值。在Go语言的字典类型中,每个键值都是由它的哈希值代表的,字典不会存储任何键值,只会存储它们的哈希值。

Map的赋值方式:
1. 定义map,赋值给map1:

Var map1 map[int]string
map1 := map[int]string{:"a", :"b", :"c"}

对于字典值来说,如果指定键没有对应的值则默认为该类型的空值。所以map1[5]会返回一个""。

但是这样的话我们就不知道map1[5]到底是""还是map1[5]没有这个值。所以go提供了另外一种写法:

e, ok := map1[]

针对字典的索引表达式可以有两个求职结果,第二个求职结果是bool类型的。它用于表明字典值中是否存在指定的键值对。

2. 用make进行初始化赋值

map2 := make(map[int]string)
map2[] = “abc”
fmt.Println(map2)

map的使用过程中需要注意以下几点:

1、map是无序的,每次打印出来的map都不会一样,它不能够通过index获取,而必须通过key获取;
2、map的长度不是固定的。和slice类似,map也是一种引用类型;
3、内置的len函数同样适用于map,返回map拥有的key的数量;
4、map的值可以很方便的修改。

问题:字典的键类型不能是哪些类型?

回答:不可以是函数类型、字典类型和切片类型。
分析:Go语言规范中规定,在键类型的值之间必须可以施加操作符“==”和“!=”,必须要支持判等操作。
由于函数类型、字典类型和切片类型不支持判等操作,所以不能是这些类型。

另外,如果键的类型是接口类型(map[interface{}]),那么键值的实际类型也不能是上述三种类型,否则会引发panic。

package main

func main() {
// 示例1。
var badMap1 = map[[]int]int{} // 这里会引发编译错误。
_ = badMap1 // 示例2。
var badMap2 = map[interface{}]int{
"": ,
[]int{}: , // 这里会引发panic。
: ,
}
_ = badMap2 // 示例3。
var badMap3 map[[][]string]int // 这里会引发编译错误。
_ = badMap3 // 示例4。
type BadKey1 struct {
slice []string
}
var badMap4 map[BadKey1]int // 这里会引发编译错误。
_ = badMap4 // 示例5。
var badMap5 map[[][][][]string]int // 这里会引发编译错误。
_ = badMap5 // 示例6。
type BadKey2Field1 struct {
slice []string
}
type BadKey2 struct {
field BadKey2Field1
}
var badMap6 map[BadKey2]int // 这里会引发编译错误。
_ = badMap6 }

该例中,用字面量声明了一个字典badMap2,并进行了初始化,包含了三个键-元素对,其中第二个键元素对的键值是[]int{2},元素值是2,从语法上来讲,这样是可以的。

这里的badMap2的类型是接口类型interface{},元素值类型为int,这样的声明不会引起什么错误,Go语言编译器也不会报错。

但是,在运行的时候,Go语言的运行时系统(runtime库)就会抛出panic错误,所以最好不要把字典类的键类型设定为任何接口类型。

如果键的类型是数组类型,那么还要确保该类型的元素类型不是函数类型、字典类型或切片类型。

比如,由于类型[1][]string的元素类型是[string],所以它也不能作为字典类型的键类型。

另外,如果键类型是结构体类型(struct),那么还要保证其中字段的类型的合法性。

为什么键类型必须支持判等操作?

因为只有哈希值和键值都相等,Go才能通过键值找到元素值。

扩展:

Q1: 应该优先考虑哪些类型作为字典的键类型?

从性能的角度讲,在“映射”的过程中,“把键值转换为哈希值”和“把要查找的键值和bucket哈希桶中的键值做比对”是两个比较耗时的操作,

因此,求哈希和判等操作的速度越快,对于的类型就越适合作为键类型。

求哈希为例,宽度越小的类型速度越快,如bool,整数类型、浮点数类型、复数类型和指针类型。
对于字符串类型,由于它的宽度是不定的,所以要看它的值的具体长度,长度越短求哈希越快。
类型的宽度是指它的单个值需要占用的字节数,如bool、int8和uint8类型的值需要占用的字节数都是1,宽度就是1.
高级类型中,数组类型的值求哈希实际上是依次求得它每个元素的哈希值并键合并,所以速度就取决于元素类型以及长度。
结构体类型的值求哈希,实际上是对它的所有字段求哈希并进行合并,所以关键在于它的各个字段的类型以及字段的数量。
对于接口类型,具体的哈希算法由值的实际类型决定。

不建议使用高级类型作为字典的键类型,因为判等速度慢,而且在他们的值中存在变数。
比如,对于一个数组,我们可以任意改变元素值,在变化前后,它代表了两个不同的键值。
把接口类型作为字段的键类型最危险,会导致panic错误,甚至程序崩溃。

Q2: 在值为nil的字典上执行读操作会成功吗?写操作呢?

demo19.go

package main

import "fmt"

func main() {
var m map[string]int key := "two"
elem, ok := m["two"]
fmt.Printf("The element paired with key %q in nil map: %d (%v)\n",
key, elem, ok) fmt.Printf("The length of nil map: %d\n", len(m)) fmt.Printf("Delete the key-element pair by key %q...\n", key)
delete(m, key) elem =
fmt.Println("Add a key-element pair to a nil map...")
//m["two"] = elem // 这里会引发panic。
}

字典是引用类型,所以当我们仅声明而不初始化一个字典类型的变量的时候,它的值会是nil。
除了添加键元素对,我们在一个值为nil的字典上做任何操作,都不会引起错误。
而如果我们要在这个值为nil的字典中添加键元素对时,Go的runtime系统会抛出一个panic。

思考题:字典类型的值是并发安全的吗?如果不是,那么我们只在字典上添加或删除键元素对的情况下,依然不安全吗?

A:go实现的map不是多协程安全的(并发访问可能导致):
fatal error: concurrent map read and map write
对字典操作最好用1.9之后新加入的sync.Map, 如果不用的话需要对goroutine加读写锁。
非原子操作需要加锁,map并发读写需要加锁,判断一个操作是否是原子的可以使用go run race命令做数据的竞争检测。

[Golang学习笔记] 09 字典的更多相关文章

  1. golang学习笔记5 用bee工具创建项目 bee工具简介

    golang学习笔记5 用bee工具创建项目 bee工具简介 Bee 工具的使用 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/instal ...

  2. golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题

    golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ...

  3. golang学习笔记19 用Golang实现以太坊代币转账

    golang学习笔记19 用Golang实现以太坊代币转账 在以太坊区块链中,我们称代币为Token,是以太坊区块链中每个人都可以任意发行的数字资产.并且它必须是遵循erc20标准的,至于erc20标 ...

  4. golang学习笔记18 用go语言编写移动端sdk和app开发gomobile

    golang学习笔记18 用go语言编写移动端sdk和app开发gomobile gomobile的使用-用go语言编写移动端sdk和app开发https://blog.csdn.net/u01249 ...

  5. golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍

    golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...

  6. golang学习笔记16 beego orm 数据库操作

    golang学习笔记16 beego orm 数据库操作 beego ORM 是一个强大的 Go 语言 ORM 框架.她的灵感主要来自 Django ORM 和 SQLAlchemy. 目前该框架仍处 ...

  7. golang学习笔记14 golang substring 截取字符串

    golang学习笔记14 golang substring 截取字符串golang 没有java那样的substring函数,但支持直接根据 index 截取字符串mystr := "hel ...

  8. golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换

    golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...

  9. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

随机推荐

  1. Linux下的Mysql的双向同步

    在主从复制的基础上实现双向同步 [更多参考] https://www.cnblogs.com/shuidao/p/3551238.html http://blog.csdn.net/i_bruce/a ...

  2. 计算机支持的最大内存与CPU之间的关系

    在使用计算机时,其最大支持的内存是由  操作系统 和 硬件 两方面决定的. 先说一下硬件方面的因素,在计算机中 CPU的地址总线数目 决定了CPU 的 寻址 范围,这种由地址总线对应的地址称作为物理地 ...

  3. Exchange 2016 CU6 安装后,发生错误 出现意外错误,无法处理您的请求

    公司的Exchange2016环境准备上线了,今天owa打不开了.出现如下图的错误,更多详细信息没有截图,但最关键的一句记下来了. X-OWA-Error Microsoft.Exchange.Dia ...

  4. 25个最佳的SSH命令

    参考文献地址(SSH原理与运用(一):远程登录): http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html 参考文献地址(SSH原理与 ...

  5. July 31st 2017 Week 31st Monday

    Elegance is the only beauty that never fades. 优雅是唯一不会褪色的美. Even the most beautiful apperace would be ...

  6. php中的雷同方法

    php中又很多的可选语法,比如echo 使用echo()和print()都可以输出文本,他们的不同之处在于print()函数有一个返回值1代表输出成功,0代表输出失败,二echo()就没有返回值了. ...

  7. 一个简单的使用matplotlib作图的例子

    #使用matplotlib作图 import numpy as np import matplotlib.pyplot as plt #x = np.linspace(start, stop, num ...

  8. [转]浅谈利用SQLite存储离散瓦片的思路和实现方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在多个项目中涉及到互联网地图的内网显示,通过自制工具完成了互联 ...

  9. ACM-SG函数之S-Nim——hdu1536 hdu1944 poj2960

    S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  10. 小程序的get和post需要注意的地方

    在进行异步请求之前先去小程序后台配置好服务器域名. get请求:header: { 'content-type':'json'}就可以. post请求:header: { 'content-type' ...