为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中迭代地图时修改地图

在 Go 中迭代地图时修改地图

Go
开心每一天1111 2022-09-19 10:41:42
鉴于以下代码,我预计会出现无限循环,但循环在某个点停止。m := make(map[int]string, 4)m[0] = "Foo"    for k, v := range m {    m[k+1] = v}我无法弄清楚引擎盖下发生了什么,因为不同的执行返回不同的输出。例如,这些是来自不同执行的几个输出:map[0:Foo 1:Foo 2:Foo 3:Foo 4:Foo 5:Foo 6:Foo 7:Foo]map[0:Foo 1:Foo]map[0:Foo 1:Foo 2:Foo]如何工作才能在特定点退出循环,退出条件是什么?range
查看完整描述

3 回答

?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

Spec:对于具有范围子句的语句,表示行为是不可预测的:

未指定映射的迭代顺序,也不保证从一次迭代到下一次迭代相同。如果在迭代期间移除尚未到达的映射条目,则不会生成相应的迭代值。如果在迭代期间创建了映射条目,则该条目可能会在迭代期间生成,也可以跳过。对于创建的每个条目以及从一次迭代到下一次迭代,选择可能会有所不同。如果映射为 ,则迭代次数为 0。nil

将元素添加到您正在测距的地图中,这些条目可能会被循环访问,也可能不会被循环访问,您不应该假设与此相关的任何事情。


查看完整回答
反对 回复 2022-09-19
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

其他答案已经解释了您在代码段中观察到的行为。


由于您的标题相当通用,但您的代码段仅涵盖在迭代地图时添加地图条目,因此这里有一个补充示例,应该说服您,在迭代地图时“交叉删除”地图条目是一个坏主意(Playground):


package main


import "fmt"


func main() {

    m := map[string]int{"foo": 0, "bar": 1, "baz": 2}

    for k := range m {

        if k == "foo" {

            delete(m, "bar")

        }

        if k == "bar" {

            delete(m, "foo")

        }

    }

    fmt.Println(m)

}

该规范说:


未指定映射的迭代顺序,也不保证从一次迭代到下一次迭代相同。如果在迭代期间移除尚未到达的映射条目,则不会生成相应的迭代值。


结果,程序输出 或 ,但无法分辨哪个。map[bar:1 baz:2]map[baz:2 foo:0]


查看完整回答
反对 回复 2022-09-19
?
MMTTMM

TA贡献1869条经验 获得超4个赞

基于语言规范:

如果在迭代期间创建了映射条目,则该条目可能会在迭代期间生成,也可以跳过。

因此,如果跳过新元素,for 循环最终会结束。


查看完整回答
反对 回复 2022-09-19
  • 3 回答
  • 0 关注
  • 87 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信