0

0

golang map 实现原理

王林

王林

发布时间:2023-05-15 11:59:36

|

821人浏览过

|

来源于php中文网

原创

在学习 golang 的过程中,map 是我们经常使用的一种数据结构,可以用来存储 key-value 对。但是,你是否想过 map 的实现原理是什么呢?在本文中,我们将探究 golang 中 map 的实现原理。

map 实现原理简介

map 实际上是一个哈希表,它的实现原理就是哈希算法。哈希表是一种根据关键字直接访问内存存储位置的数据结构,也就是说,它提供了一种将关键字映射到内存地址的方法。在哈希表中,关键字被称为“键”,通过哈希函数计算得到的内存地址被称为“桶”,桶存储了键值对。

在 Golang 中,map 是通过在桶内存区域存储键值对实现的,每个桶都有一个头部结构体,用于描述桶的状态,这个头部结构体称为“bucket”。

bucket 数据结构

立即学习go语言免费学习笔记(深入)”;

先来看一下 bucket 的数据结构:

type bmap struct {
    tophash [bucketCnt]uint8
    // data 的类型在 map 被分配空间的时候由 map 的 key 和 value 类型决定
    // 如果 key 类型和 value 类型都是未知类型,那么 data 的类型是 byte
    // 因为 byte 可以用于存储任何类型,也就是说 data 可以存储任何类型的 key 和 value
    // 在存储 key 和 value 的时候,需要将 key 和 value 转换成 uintptr,然后再转换成 byte 存储到 data 中
    // 读取 key 和 value 的时候反向操作即可
    // 因此,map 中的 key 和 value 一般都是需要转换成 uintptr 类型的
    // 这里我们可以简单地理解为 data 存储了键值对的二进制数据
    // 第一个 bucket 中如果存不下某个 key-value,还需要在第二个 bucket 中存储
    // 所以,data 的长度可以为 1 或 2
    // 当 data 的长度为 1 或 2 时,存储的键值对的个数分别为 1 或 2
    // 因此,bucket 中最多只能存储 8 个键值对
    // 否则,就需要将键值对存储在 overflow 中
    // overflow 是一个指向单链表头部的指针数组
    // 如果某个桶存储的键值对数量超过了 8,那么就将多余的键值对存储到 overflow 中
    // overflow 中的第一个 bucket 中也是能够存储 8 个键值对的,如果第一个 bucket 中存不下的话
    // 那么还需要在第二个 bucket 中继续存储
    // 所以,overflow 数组的长度也可以为 1 或 2
    // 当 overflow 数组长度为 1 或 2 时,最多存储 8 个键值对的 overflow
    // 当 overflow 数组长度为 3 时,最多存储 24 个键值对的 overflow
    // 也就是说,如果 map 中存储的键值对数量很多的话,那么可能会有很多个 overflow 桶
    // 而 overflow 数组是动态分配的,因此它的长度是不定的,只有在运行时才能确定
    data unsafe.Pointer
    // overflow 是一个指针数组,用于存储除当前桶以外的其它桶
    // 如果某个桶的键值对数量超过了 8,那么它会将多余的键值对存储到 overflow 中
    // overflow 数组中的每个元素都是一个 bucket 指针
    // 这些 bucket 指针构成了一个链表,也就是所谓的 overflow 链表
    overflow *[]*bmap
    // 这里存储的是这个 bucket 当前存储的键值对的个数
    count int16
    // flags 存储了 bucket 的标志
    // 一个 bucket 可能会有如下三种状态:
    // 1. empty,表示这个 bucket 没有存储任何键值对
    // 2. iterator,表示这个 bucket 正在被访问,不能再被其它操作使用
    // 3. deleted,表示这个 bucket 存储的键值对已经被删除了
    // 注意,该标志位只有在 GC 达到一定阈值后才会被置为 true,而且并不是立即删除键值对,而是在下一次 GC 的时候才会内存回收
    flags uint8
    // Bmap 的类型标记
    // Bmap 用来标识存储于上文中 data 指针中的数据类型
    // 如果 data 中存储的是 int,那么 Bmap 的值为 hmap.BmapInt
    // 如果 data 中存储的是 string,那么 Bmap 的值为 hmap.BmapString
    // 如果 data 中存储的是 interface{},那么 Bmap 的值为 hmap.BmapInterface
    // 如果 data 中存储其他类型,那么 Bmap 的值为 hmap.BmapOther
    BmapType uint16
    // 与该 bucket 相关联的 key 的类型
    tophash0 uint8
}

从上面的定义中,我们可以看到,bucket 存储了以下信息:

  • tophash:用于快速筛选出不匹配的 key;
  • data:存储键值对的数据;
  • overflow:存储 overflow 链表的指针数组;
  • count:存储了当前 bucket 中存储的键值对的个数,最多为 8;
  • flags:存储了 bucket 的一些状态信息;
  • BmapType:存储了 data 中存储数据的类型;
  • tophash0:与该 bucket 相关联的 key 的类型。

实现原理

多奥淘宝客程序API免费版 F8.0
多奥淘宝客程序API免费版 F8.0

多奥淘宝客程序免费版拥有淘宝客站点的基本功能,手动更新少,管理简单等优点,适合刚接触网站的淘客们,或者是兼职做淘客们。同样拥有VIP版的模板引擎技 术、强大的文件缓存机制,但没有VIP版的伪原创跟自定义URL等多项创新的搜索引擎优化技术,除此之外也是一款高效的API数据系统实现无人值守全自动 化运行的淘宝客网站程序。4月3日淘宝联盟重新开放淘宝API申请,新用户也可使用了

下载

由于 map 存储的数据是键值对,而且键值对的 key 值是不可重复的并且能够进行比较大小操作,我们可以采用哈希函数将 key 值转换为一个唯一的哈希值,然后将哈希值作为 key 值对应的索引,将 value 值存储在该索引上。

在 Golang 中,每一个 map 都有一个哈希表,这个哈希表实际上就是一段连续的存储空间,可以存储若干个桶(bucket),每个桶都是一个 bucket 类型的结构体。

那么哈希表的大小是如何确定的呢?它是在 map 创建时动态分配内存而来的,首次分配空间时候使用的默认大小为 8 个桶。如果第一次增加元素的时候,桶的数量不够,则哈希表的大小会扩容,并重新计算每个元素在哈希表中的索引位置。

在 Golang 中,哈希函数的作用主要是将 key 值散列化,使其更方便的定位到哈希表中的一个桶,从而加速查找 key 值对应的 value 值。在 Golang 中,哈希函数的实现采用了 MurmurHash3 算法。

由于哈希函数是将 key 映射到一个整数,因此不同的 key 值可能映射到相同的索引。这种情况被称为哈希冲突。当出现哈希冲突时,Golang 采用链表法来进行解决,将相同索引上的键值对存储在该索引的链表中,这些键值对就称为 overflow。

总结

Golang 的 map 实现原理主要依赖哈希表和哈希函数。哈希函数用于散列化 key 值,将其映射到哈希表中的一个桶,从而加速查找 value 值的操作。哈希表由若干个桶组成,每个桶由一个 bucket 类型的结构体表示,存储了键值对的信息。当哈希表中的同一索引位置上存在多个键值对时,采用链表法存储 overflow。Golang 中的 map 实际上就是一个动态哈希表,可以动态地调整哈希表的大小。在使用 map 时,需要注意避免哈希冲突和包含无法比较大小的类型作为 key。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号