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;其中一方关机…

SCI论文发表很容易【2】:论文修改稿

大家已经投完了稿子,也在中途因为审稿周期较长而催审了稿子,那么当我们的稿子需要返修时,怎么开展呢,下面是模板: 注:如果杂志社有特定的要求和模板,必须采用杂志社的模板,否则可以利用下面的模板。 2.1 国内期刊回复专家意见 (1)《中国管理科学》专家回复 论文“…

C++学习之基于apr构建不定长内存池申请分配

Apache安装 Apache使用 #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <chrono> #include <thread> #include <vector>#include <apr.h> #include <apr_pools.h> #incl…

Kubernetes中使用NVIDIA DCGM-Exporter监控GPU

在使用NVIDIA GPU的Kubernetes集群中,监控GPU的健康状态和性能对于维护系统的最佳性能至关重要。一种有效的方法是利用NVIDIA数据中心GPU管理器(DCGM)Exporter与Prometheus和Grafana结合使用。在本指南中,我们将演示如何在Kubernetes环境中设置GPU监控。 ​​实例信息查询…

@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领…

pyqt5与selenium混合使用心得

最近想爬一个网站的数据,有用户名密码 但登陆时验证码比较麻烦,是实时变化的一个动态地址 主要给客户使用的 所以无需全自动抓取 def send_request(driver, url, params, method=POST):if method == GET:parm_str = for key, value in params.items():parm_str = parm_st…

MQ组件之RabbitMQ学习

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

【LeetCode-46.全排列】

题目详情&#xff1a; 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; …

字符型数据详解

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.…

Linux的常用命令-1

ifconfig:看网络 ifconfig -a:看所以包括禁掉的网卡 ifconfig 网卡名 down:关网卡 ifconfig 网卡名 up:开网卡 ps -ef|grep 服务名&#xff1a;显示进程&#xff08;ps -ef|grep sshd&#xff09; kill -9 进程编号&#xff1a;杀进程 clear:清屏 exit:退出shell 切用户 …

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

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;一定是先考虑一个维度再按照另一个维度来重新考虑排序。 两…