map 在扩容后,会发生 key 的搬迁,原来落在同一个 bucket 中的 key,搬迁后,有些 key 就要远走高飞了(bucket 序号加上了 2^B)。而遍历的过程,就是按顺序遍历 bucket,同时按顺序遍历 bucket 中的 key。搬迁后,key 的位置发生了重大的变化,有些 key 飞上高枝,有些 key 则原地不动。这样,遍历 map 的结果就不可能按原来的顺序了。
当然,如果我就一个 hard code 的 map,我也不会向 map 进行插入删除的操作,按理说每次遍历这样的 map 都会返回一个固定顺序的 key/value 序列吧。的确是这样,但是 Go 杜绝了这种做法,因为这样会给新手程序员带来误解,以为这是一定会发生的事情,在某些情况下,可能会酿成大错。
当然,Go 做得更绝,当我们在遍历 map 时,并不是固定地从 0 号 bucket 开始遍历,每次都是从一个随机值序号的 bucket 开始遍历,并且是从这个 bucket 的一个随机序号的 cell 开始遍历。这样,即使你是一个写死的 map,仅仅只是遍历它,也不太可能会返回一个固定序列的 key/value 对了。
多说一句,“迭代 map 的结果是无序的”这个特性是从 go 1.0 开始加入的。
答案解析来自:https://golang.design/go-questions/map/unordered/
“迭代 map 的结果是无序的”这个特性是从 go 1.0 开始加入的。
打卡
map 的key要转换成hash存到桶里面,所以无法做出有价值的排序。go1.15之后,go官方故意把遍历的顺序搞乱,同一个map实例每次遍历的顺序都故意搞成不一样。
mark 确实是这样
这逻辑真的难接受,但也只能接受
mark
mark
打卡
Go 做得更绝,当我们在遍历 map 时,并不是固定地从 0 号 bucket 开始遍历,每次都是从一个随机值序号的 bucket 开始遍历,并且是从这个 bucket 的一个随机序号的 cell 开始遍历。这样,即使你是一个写死的 map,仅仅只是遍历它,也不太可能会返回一个固定序列的 key/value 对了 ----学习了
多说一句,“迭代 map 的结果是无序的”这个特性是从 go 1.0 开始加入的。
😀
map是根据哈希表实现的,而哈希表根据不同的哈希键来存储不同的哈希值,不同的哈希函数得到的哈希值也不同,为什么要设计成无序的呢?因为哈希表本身的存在就是为了查询的速率而不是他的顺序本身,如果为了保证顺序就会额外的操作进而影响查询的性能。