Go源码版本1.13.8
前言
写博客的目的?
把自己学习知识进行一个总结。同时把一些可能困难、复杂难以理解的东西自我消化吸收后,简单化输出,降低他人的学习成本,提高他人的学习效率,主要为如下两点:
自我学习的总结过程
简化他人学习成本的结果
其次,或多或少存在自己学习过程中理解不到位或者错误的地方希望大家可能及时帮我纠正,感谢以及说一声抱歉。
为什么博客更新的这么慢?
学习的难度在不断的增加,产出越来越慢
比以前懒了?
今天要分享的是主要内容是Go语言Map底层实现
,目的让大家快速了解Go语言Map
底层大致的实现原理。读完本篇文章你可以获得收益、以及我所期望你能获取的收益如下:
收益序号 | 收益描述 | 掌握程度 |
---|---|---|
收益1 | 大致对Go语言Map底层实现有一个了解 | 必须掌握 |
收益2 | 大致知道Go语言Map是如何读取数据的 | 必须掌握 |
收益3 | 熟悉Go语言Map底层核心结构体hmap |
可选 |
收益4 | 熟悉Go语言Map底层核心结构体bmap |
可选 |
收益5 | 熟悉Go语言Map底层里的溢出桶 | 可选 |
收益6 | 熟悉Go语言Map是如何读取数据的 | 可选 |
收益1和收益2是看了本篇文章希望大家必须掌握的知识点,其他的为可选项,如果你对此感兴趣或者已经掌握了收益1、2可以继续阅读此处的内容。
对于本篇文章的结构主要按如下顺序开展:
简单看看一般Map的实现思路
Go语言里Map的实现思路(入门程度:包含收益1、2)
Go语言里Map的实现思路(熟悉程度:包含收益3、4、5、6)
其次,本篇文章主要以Map的读来展开分析,因为读弄明白了,其他的写、更新、删除等基本操作基本都可以猜出来了,不是么????。
简单看看一般Map的实现思路
直入主题,一般的Map会包含两个主要结构:
数组:数组里的值指向一个链表
链表:目的解决hash冲突的问题,并存放键值
大致结构如下:
读取一个key值的过程大致如下:
key
|
v
+------------------------------------+
| key通过hash函数得到key的hash |
+------------------+-----------------+
|
v
+------------------------------------+
| key的hash通过取模或者位操作 |
| 得到key在数组上的索引 |
+------------------------------------+
|
v
+------------------------------------+
| 通过索引找到对应的链表 |
+------------------+-----------------+
|
v
+------------------------------------+
| 遍历链表对比key和目标key |
+------------------+-----------------+
|
v
+------------------------------------+
| 相等则返回value |
+------------------+-----------------+
|
v
value
接着我们来简单看看Go语言里Map的实现思路。
Go语言里Map的实现思路(入门程度)
包含收益1、2
Go语言解决hash冲突不是链表,实际主要用的数组(内存上的连续空间),如下图所示:
备注:后面我们会解释上面为啥用的“主要”两个字。
但是并不是只使用一个数组(连续内存空间)存放键和值,而是使用了两个数组分别存储键和值,图示如下:
上图中:
分别对应的是两个核心的结构体
hmap
和bmap
bmap
里有两个数组分别存放key和value
把上面简化的关系转换一下,其实就是这样的一个大致关系,如下图所示:
我们通过一次读操作
为例,看看读取某个key的值的一个大致过程: