目录
  • 一、为什么是无序的?
  • 二、go 为什么要这么做?
  • 三、遍历是否真的无序的
    • 1.第一次遍历
    • 2.第二次遍历
  • 四、如何才能得到有序的键值对
    • 总结

      一、为什么是无序的?

      开门见山,先上源码

      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无序内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!