详解Golang Map中的key为什么是无序的

 更新时间:2022年02月17日 09:10:08   作者:头秃猫轻王  
本文主要介绍了Golang Map中的key为什么是无序的,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一、为什么是无序的?

开门见山,先上源码

func mapiterinit(t *maptype, h *hmap, it *hiter) {
 
	// decide where to start
	r := uintptr(fastrand())
	if h.B > 31-bucketCntBits {
		r += uintptr(fastrand()) << 31
	}
	
	mapiternext(it)
}

Go 当我们在遍历 map 时,并不是固定地从第一个数开始遍历,每次都是从一个位置开始遍历。即使是一个不会改变的的 map,仅仅只是遍历它,也不太可能会返回一个固定顺序了。
也就是说,GO语言从语言上进行 Map 的无序。

二、GO 为什么要这么做?

其实主要是因为 map 在扩容后,可能会将部分 key 移至新内存,那么这一部分实际上就已经是无序的了。而遍历的过程,其实就是按顺序遍历内存地址,同时按顺序遍历内存地址中的 key。但这时已经是无序的了。

当然有人会说,如果我就一个 map,我保证不会对 map 进行修改删除等操作,那么按理说没有扩容就不会发生改变。但也是因为这样,GO 才在源码中
加上随机的元素,将遍历 map 的顺序随机化,用来防止使用者用来顺序遍历。而这是有风险的代码,在GO 的严格语法规则下,是坚决不提倡的。

三、遍历是否真的无序的

1.第一次遍历

代码如下(示例):

package main

import "fmt"

func main() {

	noSortMap := map[int]int{
		1: 1,
		2: 2,
		3: 3,
		4: 4,
		5: 5,
		6: 6,
	}

	for k, v := range noSortMap {

		fmt.Println("key: ", k, "value: ", v)
	}

}

结果果然不出所料,并没有从第一个数开始

第一次遍历

2.第二次遍历

代码同上:

结果果然不出所料,与第一次都不相同

在这里插入图片描述

四、如何才能得到有序的键值对

我们需要使用 切片(Slice) 来进行控制,

1.详细代码

代码如下(示例):

package main

import (
	"fmt"
	"sort"
)

func main() {

	noSortMap := map[int]int{
		1: 1,
		2: 2,
		3: 3,
		4: 4,
		5: 5,
		6: 6,
	}

	var noSortSlice []int
	for k, v := range noSortMap {

		noSortSlice = append(noSortSlice, k)
		fmt.Println("key: ", k, "value: ", v)
	}

	fmt.Println(noSortSlice)
	// 排序
	sort.Ints(noSortSlice)
	sortSlice := noSortSlice
	fmt.Println(sortSlice)
	for _, k := range sortSlice {

		fmt.Println("key: ", k, "value: ", noSortMap[k])
	}
	
}

先将无序的key 放进切片中

无序

再将无序的切片 调用 sort包的 Ints 方法排序

排序后再遍历切片,此时切片有序,则 map 的键值对也是有序的

有序

总结

不要依赖map遍历时返回的key顺序,采用随机选择遍历起始位置的方式使得遍历时返回是乱序的。如果想得到有序键值,请依靠有序切片进行访问来得到有效的有序 Map

到此这篇关于详解Golang Map中的key为什么是无序的的文章就介绍到这了,更多相关Golang Map key无序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang Mutex 原理详细解析

    Golang Mutex 原理详细解析

    这篇文章主要介绍了Golang Mutex原理详细解析,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • Go日志框架zap增强及源码解读

    Go日志框架zap增强及源码解读

    这篇文章主要为大家介绍了Go日志框架zap增强及源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 详解在Go语言单元测试中如何解决Redis存储依赖问题

    详解在Go语言单元测试中如何解决Redis存储依赖问题

    在编写单元测试时,除了 MySQL 这个外部存储依赖,Redis 应该是另一个最为常见的外部存储依赖了,本文就来讲解下如何解决 Redis 外部依赖,文章通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • Golang中的包及包管理工具go mod详解

    Golang中的包及包管理工具go mod详解

    这篇文章主要介绍了Golang中的包及包管理工具go mod,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • go内存缓存如何new一个bigcache对象示例详解

    go内存缓存如何new一个bigcache对象示例详解

    这篇文章主要为大家介绍了go内存缓存如何new一个bigcache对象示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 总结Golang四种不同的参数配置方式

    总结Golang四种不同的参数配置方式

    这篇文章主要介绍了总结Golang四种不同的参数配置方式,文章围绕主题展开详细的内容戒杀,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • Go sync WaitGroup使用深入理解

    Go sync WaitGroup使用深入理解

    这篇文章主要为大家介绍了Go sync WaitGroup使用深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Go语言集成开发环境之VS Code安装使用

    Go语言集成开发环境之VS Code安装使用

    VS Code是微软开源的一款编辑器,插件系统十分的丰富,下面介绍如何用VS Code搭建go语言开发环境,需要的朋友可以参考下
    2021-10-10
  • go 如何修改postgresql的配置参数

    go 如何修改postgresql的配置参数

    这篇文章主要介绍了go 如何修改postgresql的配置参数,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • 轻松构建Go应用的Dockerfile

    轻松构建Go应用的Dockerfile

    本文介绍了如何制作一个用于构建和运行Go应用程序的Docker镜像的Dockerfile的相关资料,需要的朋友可以参考下
    2023-10-10

最新评论