Go——map

一.map介绍和使用

        map是一种无序的基于key-value的数据结构,Go语言的map是引用类型,必须初始化才可以使用。

        1. 定义

        Go语言中,map类型语法如下:

map[KeyType]ValueType
  • KeyType表示键类型
  • ValueType表示值类型

        map类型的变量默认初始值为nil,需要使用make函数来分配内存。语法为:

make(map[KeyType]ValueType, [cap])map[KeyType]ValueType{} //底层也是使用的makemap[KeyType]Value{ //底层也是使用的makekey:value,key:value,...
}

        其中cap表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map的时候就为其指定一个合适的容量。 

        可以使用len()内置函数来获取map键值对的个数。

        注意:map保存的键值对中,键不能被修改,只能修改值。

        2.基本使用

package mainimport "fmt"func main() {scoreMap := make(map[string]int, 8)scoreMap["张三"] = 100scoreMap["小明"] = 90fmt.Println(scoreMap)fmt.Printf("key num is %d\n", len(scoreMap))fmt.Println(scoreMap["小明"])fmt.Printf("type(scoreMap)=%T\n", scoreMap)
}

map也支持在声明时填充元素: 

package mainimport "fmt"func main() {userInfo := map[string]string{"username": "zhansan","password": "123456",}fmt.Println(userInfo)
}

        3. 判断某个键是否存在

        Go语言中有个判断map中的键是否存在的特殊写法:

value, ok := map[key]

        例子:

package mainimport "fmt"func main() {userInfo := map[string]string{"username": "zhansan","passward": "123456",}value, ok := userInfo["passward"]if ok {fmt.Println(value)} else {fmt.Println("passward is not exit")}value, ok = userInfo["sex"]if ok {fmt.Println(value)} else {fmt.Println("sex is not exit")}
}

        4. map的遍历

        遍历key和value:

package mainimport "fmt"func main() {scoreMap := make(map[string]int, 8)scoreMap["小明"] = 100scoreMap["张三"] = 80scoreMap["李四"] = 60for key, value := range scoreMap {fmt.Printf("scoreMap[%s] = %d\n", key, value)}
}

         只遍历key:

注意:遍历map时的元素顺序与添加键值对的顺序无关。 

        5. 删除键值对

        使用delete()内置函数从map中删除一组键值对,格式如下:

delete(map, key)//map:为需要删除键值对的map
//key:表示要删除键值对的键
package mainimport "fmt"func main() {scoreMap := make(map[string]int, 8)scoreMap["小明"] = 100scoreMap["张三"] = 80scoreMap["李四"] = 60value, ok := scoreMap["李四"]if ok {fmt.Println(value)} else {fmt.Println("李四 is not exit")}//删除键值对delete(scoreMap, "李四")value, ok = scoreMap["李四"]if ok {fmt.Println(value)} else {fmt.Println("李四 is not exit")}
}

        6. 按照指定顺序遍历map

        实际时先获取到所有的键,将键设置成指定顺序,再通过键来遍历map。

package mainimport ("fmt""math/rand""sort""time"
)func main() {rand.Seed(time.Now().UnixNano()) //初始化随机种子scoreMap := make(map[string]int, 200)for i := 0; i < 100; i++ {key := fmt.Sprintf("stu%02d", i)scoreMap[key] = rand.Intn(100) //获取0-100的随机数//fmt.Println(key, scoreMap[key])}keys := make([]string, 0, 200)//保存key//按照排序后的key遍历scoreMapfor key := range scoreMap {keys = append(keys, key)}//fmt.Println(keys)sort.Strings(keys) //对keys进行排序for _, key := range keys {fmt.Printf("scoreMap[%s] = %d\n", key, scoreMap[key])}
}

        7. 元素为map类型的切片

package mainimport "fmt"func main() {mapSlice := make([]map[string]string, 3, 10) //并没有为map分配地址空间for index, val := range mapSlice {fmt.Printf("mapSlice[%d] = %v\n", index, val)}//分配地址空间for index, _ := range mapSlice {mapSlice[index] = make(map[string]string, 10)}fmt.Println("---------插入键值对后---------")//插入键值对mapSlice[0]["name"] = "张三"mapSlice[0]["passwd"] = "123123"mapSlice[1]["name"] = "李四"mapSlice[1]["passwd"] = "321321"mm := map[string]string{"name":   "小明","passwd": "123465",}mapSlice = append(mapSlice, mm)for index, val := range mapSlice {fmt.Printf("mapSlice[%d] = %v\n", index, val)}
}

        8. 值为切片类型的map

package mainimport "fmt"func main() {sliceMap := make(map[string][]string, 10) //没有为slice分配空间sliceMap["中国"] = make([]string, 0, 10)sliceMap["中国"] = append(sliceMap["中国"], "北京", "上海", "长沙")key := "美国"value, ok := sliceMap[key]if !ok {value = make([]string, 0)}value = append(value, "芝加哥", "华盛顿")sliceMap[key] = valuefor key, val := range sliceMap {fmt.Printf("sliceMap[%s] = %v\n", key, val)}
}

二.map底层原理

         Go语言的map有两个重要的数据结构 hmap和bmap。

        2.1 map头部数据结构——hmap

        hmap中有几个重要的属性:

  • count:记录了map中实际元素的个数
  • B:控制哈希桶的个数为2^B个
  • buckets:是一个指向长度为2^B大小的类型为bmap的数组
  • oldbuckets:与buckets一样也是指向一个多桶的数组,不同的是oldbuckets指向的是旧桶的地址,当oldbuckets不为空时,表示map正处于扩容阶段。
type hmap struct {// map中元素的个数,使用len返回就是该值count     int// 状态标记// 1: 迭代器正在操作buckets// 2: 迭代器正在操作oldbuckets // 4: go协程正在像map中写操作// 8: 当前的map正在增长,并且增长的大小和原来一样flags     uint8// buckets桶的个数为2^BB         uint8 // 溢出桶的个数noverflow uint16 // key计算hash时的hash种子hash0     uint32// 指向的是桶的地址buckets    unsafe.Pointer// 旧桶的地址,当map处于扩容时旧桶才不为niloldbuckets unsafe.Pointer //扩容之后数据迁移的计数器,记录下次迁移的位置,当nevacuate>旧桶元素个数,数据迁移完nevacuate  uintptr // 额外的map字段,存储溢出桶信息extra *mapextra
}

        创建一个map实际是创建一个指针,指向hmap结构。

        2.2 bmap

        bmap是每一个桶的数据结构,每一个bmap包含8个key和value。

type bmap struct {tophash [bucketCnt]uint8        // len为8的数组,用来快速定位key是否在这个bmap中// 一个桶最多8个槽位,如果key所在的tophash值在tophash中,则代表该key在这个桶中
}

         上面是bmap的静态结构,在编译过程中runtime.bmap会扩展成以下结构:

  • topbits :用来快速定位桶中键值对的位置。
  • keys:键值对的键
  • values:键值对的值
  • overflow:当8个key满的时候,需要新创建一个桶,overflow保存下一个桶的地址。

细节:

        这里将键和键保存到了一起,值和值保存在了一起,为什么不讲键和值保存在一起?

        因为键和值的类型可能不同,结构体内存对齐会浪费空间。

type bmap struct{topbits  [8]uint8keys     [8]keytypevalues   [8]valuetypepad      uintptr        // 内存对齐使用,可能不需要overflow uintptr        // 当bucket 的8个key 存满了之后// overflow 指向下一个溢出桶 bmap,// overflow是uintptr而不是*bmap类型,保证bmap完全不含指针,是为了减少gc,溢出桶存储到extra字段中
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/762559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络原理(4)——TCP协议的特性

目录 一、滑动窗口 1、ack丢了 2、数据丢了 二、流量控制&#xff08;流控&#xff09; 三、拥塞控制 拥塞窗口动态变化的规则 四、延时应答 五、捎带应答 六、面向字节流 七、异常情况 &#xff08;1&#xff09;进程崩溃了 &#xff08;2&#xff09;其中一方关机…

@arco.design radioGroup 组件手写 beforeChange 方法

官方是没有提供 beforeChange 事件的&#xff0c;只能自己写一个 子组件&#xff08;CustomRadioGroup&#xff09; <template><a-radio-group :model-value"modelValue" change"onRadioChange"><a-radio v-for"item in list" …

蓝桥杯-模拟-旋转图片

题目 思路 Python中range() 函数的使用介绍_python指定范围内的整数-CSDN博客 range(start, stop, step)&#xff1a;生成一个序列包含start到stop-1的整数&#xff0c;其中步长为step 代码 n, m map(int, input().split()) a [list(map(int, input().split())) for _ in…

借教室与差分

原题 题目描述 在大学期间&#xff0c;经常需要租借教室。 大到院系举办活动&#xff0c;小到学习小组自习讨论&#xff0c;都需要向学校申请借教室。 教室的大小功能不同&#xff0c;借教室人的身份不同&#xff0c;借教室的手续也不一样。  面对海量租借教室的信息&…

MySQL 锁机制

优质博文&#xff1a;IT-BLOG-CN 定义&#xff1a;锁是计算机协调多个进程或线程并发访问某一资源的机制。 一、表锁&#xff08;偏读&#xff09; MyISAM 引擎&#xff0c;开销小&#xff0c;加锁快&#xff0c;无死锁、锁定粒度大、发生锁冲突的粒度最高&#xff0c;并发度…

【MySQL】对表的相关操作(DDL)

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习计网、mysql和算法 ✈️专栏&#xff1a;MySQL学习 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac…

GPT-5可能会在今年夏天作为对ChatGPT的“实质性改进”而到来

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

MQ组件之RabbitMQ学习

MQ组件之RabbitMQ入门 同步调用和异步调用 在微服务架构中&#xff0c;服务之间的调用有同步调用和异步调用两种方式。 我们使用OpenFeign去调用是同步调用&#xff0c;同步调用的缺点很明显&#xff0c;在下图的场景中&#xff0c;支付完成后需要调用订单服务、仓库服务、短…

字符型数据详解

1 字符常量 C的字符常量是用单撇号括起来的一个字符。如a,x,D,?,$等都是字符常量。注意,a和A是不同的字符常量。 除了以上形式的字符常量外,C还允许用一种特殊形式的字符常量&#xff0c;就是以一个“\”开头的字符序列。例如,前面已经遇到过的&#xff0c;在printf函数中的…

DPDK and Trex环境指南

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、测试拓扑图 二、VirtualBox的网卡配置 三、DPDK支持的网卡 四、DPDK安装 1.DPDK向导 1). 英文向导 2). 中文向导 2.DPDK源码下载 3.DPDK源码解压 4.…

今日问题:动态分配内存出错

2024.3.22 在搜素了许多文章和查阅了许多博客后依然没有找到问题所在&#xff0c;最后无意之间翻看以前的关于动态内存管理的代码后发现&#xff1a; 没加头文件&#xff1a;#include<stdlib.h> 苦笑不得了属于是 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio…

蓝桥杯day7刷题日记

P8697 [蓝桥杯 2019 国 C] 最长子序列 思路&#xff1a;直接遍历&#xff0c;和子序列相同就记录&#xff0c;不然就下一位 #include <iostream> #include <string> using namespace std; int res;int main() {string s,t;cin>>s>>t;int i0,j0;while…

关于msvcp140.dll丢失的解决方法详情介绍,修复dll文件的安全注意事项

在使用电脑的过程中&#xff0c;是否有遇到过关于msvcp140.dll丢失的问题&#xff0c;遇到这样的问题你是怎么解决的&#xff0c;都有哪些msvcp140.dll丢失的解决方法是能够完美解决msvcp140.dll丢失问题的&#xff0c;今天小编将带大家去了解msvcp140.dll文件以及分析完美解决…

代码随想录 Day-23

力扣题目 406.根据身高重建队列 思路 这里可以看出来是有两个维度考虑&#xff0c;和力扣题目 135.分发糖果&#xff08;可以看我day-22的文章&#xff09; 有点类似。 因此遇到这种两个维度权衡的时候&#xff0c;一定是先考虑一个维度再按照另一个维度来重新考虑排序。 两…

innodb 的 buffer pool 管理 page

page 页结构 page是整个InnoDB存储的最基本构件&#xff0c;也是InnoDB磁盘管理的最小单位&#xff0c;与数据库相关的所有内容都存储在这种Page结构里。 Page分为几种类型&#xff0c;常见的页类型有 数据页(Btree Node)Undo页(Undo Log Page)系统页(System Page)事务数据页 …

PC显示字体和浏览器的字体不一致

1&#xff1a;设置了PC的区域&#xff0c;显示字符&#xff0c; 2&#xff1a;导致浏览器显示的字符一半大一半小 3&#xff1a;为什么去设置这个&#xff0c;因为担心封号 4&#xff1a;不让它检测出我是他大佬

【C++初阶】第七站:string类的初识(万字详解、细节拉满)

前言&#xff1a; &#x1f4cd;本文知识点&#xff1a;string的初识 &#x1f4a8;个人博客:Dream_Chaser&#xff5e;-CSDN博客 &#x1f6a9;本专栏&#xff1a;C 目录 一、什么是STL 二、STL的六大组件 三、STL的缺陷 四、为什么学习string类&#xff1f; 五、标准库中…

云ERP vs 本地ERP:优劣对比与选择指南

在性能方面&#xff0c;本地ERP需要需要较高级别的计算机系统和其他设备来确保其高效运行。如果企业的计算机设备不够先进&#xff0c;那么选择本地ERP可能导致系统性能下降。而云ERP解决方案则能保证性能&#xff0c;只要企业拥有稳定的互联网连接即可。 在成本方面&#xff0…

Linux的基本使用

1.Linux的背景 1.1什么Linux Linux是⼀个操作系统.和Windows是"并列"的关系. 1.2Linux系统的优势 1. 开源(意味着免费,便宜) 2. 稳定(Linux可以运⾏很多年,都不会发⽣重⼤问题) 3. 安全(Linux只有管理员或者特定⽤⼾才能访问Linux内核) 4. ⾃由(不会被强加商业产品和…

EasyCloud软件简介

运行环境&#xff1a;Win10 PCL1.9 VTK8.1 Qt5.12 VS2017 基于PCL点云库的三维点云数据处理软件 1&#xff0e;软件用户界面 本软件的用户界面主要包括以下几个部分&#xff08;如图1&#xff09;&#xff1a; [1]菜单栏&#xff0c;将软件功能模块划分为不同菜单&…