[Golang学习笔记] 09 字典
字典(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 字典的更多相关文章
- golang学习笔记5 用bee工具创建项目 bee工具简介
golang学习笔记5 用bee工具创建项目 bee工具简介 Bee 工具的使用 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/instal ...
- golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题
golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ...
- golang学习笔记19 用Golang实现以太坊代币转账
golang学习笔记19 用Golang实现以太坊代币转账 在以太坊区块链中,我们称代币为Token,是以太坊区块链中每个人都可以任意发行的数字资产.并且它必须是遵循erc20标准的,至于erc20标 ...
- golang学习笔记18 用go语言编写移动端sdk和app开发gomobile
golang学习笔记18 用go语言编写移动端sdk和app开发gomobile gomobile的使用-用go语言编写移动端sdk和app开发https://blog.csdn.net/u01249 ...
- golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍
golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...
- golang学习笔记16 beego orm 数据库操作
golang学习笔记16 beego orm 数据库操作 beego ORM 是一个强大的 Go 语言 ORM 框架.她的灵感主要来自 Django ORM 和 SQLAlchemy. 目前该框架仍处 ...
- golang学习笔记14 golang substring 截取字符串
golang学习笔记14 golang substring 截取字符串golang 没有java那样的substring函数,但支持直接根据 index 截取字符串mystr := "hel ...
- golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换
golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...
- golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题
golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...
随机推荐
- [EffectiveC++]item12:copy all parts of an object
在小书C++中,4.2.2 派生类的构造函数和析构函数的构造规则(103页) 在定义派生类对象时,构造函数执行顺序如下: 基类的构造函数 对象成员的构造函数 派生类的构造函数.
- Java.io 包(字节流)
I/O流概述 在 Java 中,把不同类型的输入.输出源抽象为流(Stream),而其中输入或输出的数据则称为数据流(Data Stream),用统一的接口表示,从而使程序设计简单明了.流是一组有顺序 ...
- N个苹果分给M个人,有多少种分法
每次分配一个苹果出去,然后再分配N-1个苹果.这里有个注意的地方就是,分那1个苹果的时候,假设还有N个苹果,不是从第一个人开始分,而是从N+1个苹果分配的位置开始,不然的话会产生重复的解.所以i=p不 ...
- Who are you, What is the science
Please read: 地球月球有多大? 我们乃至我们赖以生存的地球, 甚至是我们硕大的银河系放到茫茫大宇中真的不过是一粒尘埃, 我们司空见惯的事物,我们习以为常的生活,我们笃定信奉的科学, 是不 ...
- Java虚拟机12:虚拟机性能监控与故障处理工具
前言 定位系统问题的时候,知识.经验是基础,数据是依据,工具是运用知识处理数据的手段.这里说的数据包括:运行日志.异常堆栈.GC日志.线程快照.堆转储快照等.经常使用适当的虚拟机监控和分析的工具可以加 ...
- POJ 3261 Milk Patterns 【后缀数组 最长可重叠子串】
题目题目:http://poj.org/problem?id=3261 Milk Patterns Time Limit: 5000MS Memory Limit: 65536K Total Subm ...
- Ubuntu 14.04 系统安装后无法上网的问题(eth0识别不出)
Ubuntu 14.04 1.网口处网线状态等正常跳动 2.ifconfig 指令查询不到网卡信息 说明缺少了网卡驱动. 使用 lspci 指令查看系统中所有的驱动信息,找到 Ethernet Con ...
- 在 Linux 下搭建 Git 服务器(yum安装)
服务端(linux): 1. 安装git [root@localhost ~]# yum -y install git 2. 增加一个git账户 为了管理的方便,在linux下面增添一个 " ...
- Yum 下载安装包及对应依赖包
Yum 下载安装包及对应依赖包: 安装该软件:yum install -y yum-plugin-downloadonly 以下载 openssh-server 为例 yum install -y o ...
- SSM框架优缺点和spring boot 比起优缺点是什么?
一.SSM优缺点应该分开来说的,比如 1)spring 不说了,核心ioc.aop技术,ioc解耦,使得代码复用,可维护性大幅度提升,aop提供切面编程,同样的增强了生产力. 2)spring mvc ...