Go语言遍历map时动态修改map为何未出现无限循环?
Go map range遍历行为答疑
问题复现
你给出的测试代码如下:
m := make(map[int]string, 4) m[0] = "Foo" for k, v := range m { m[k+1] = v }
多次运行会得到长度不一的map,不会触发预期的无限循环。
map range遍历的底层逻辑
Go的map遍历逻辑在设计上就明确不保证稳定顺序,核心规则如下:
- 遍历启动时,首先会生成一个随机的起始偏移量,从偏移位置对应的桶开始向后遍历所有桶,遍历过的桶不会重复访问
- 遍历过程中如果在未被遍历的桶中新增键值对,该键值对有概率被本次遍历捕获;如果新增在已经遍历完成的桶中,该键值对绝对不会被本次遍历处理
- 遍历过程中map如果触发扩容,迭代器会自动处理新旧桶的搬迁逻辑,不会出现遍历遗漏或崩溃
不会进入无限循环的原因
range遍历map的终止条件非常明确:当迭代器完成所有桶的遍历后,就会直接退出循环,不管遍历过程中新增了多少键值对。
你给出的代码里,每次循环往map里插入k+1的新键,这些新键只会在落到还没被遍历的桶里时,才会被后续的循环迭代处理,一旦所有桶都被遍历完成,循环就会终止,不可能无限执行。
每次运行结果不一致的原因
因为遍历启动时的起始偏移量是随机的,每次运行时桶的遍历顺序、新增键落到未遍历桶的概率都不同,所以最终能被遍历到的新增键数量不一样,输出的map长度自然不固定。
内容的提问来源于stack exchange,提问作者Mpac
相关产品推荐
相关产品推荐

