使用反射更改键从地图中删除键?这是一个错误吗?

时间:2014-04-29 18:06:54

标签: go

我正在尝试使用反射从两个地图中删除相同的键。但是,从第一个映射中删除它会导致更改键值。这是WAI还是一个bug。

代码(http://play.golang.org/p/MIkFP_Zrxb):

func main() {
    m1 := map[string]bool{"a": true, "b": true}
    m2 := map[string]bool{"a": true, "b": true}

    fmt.Println(m1)

    v1 := reflect.ValueOf(m1)
    k := v1.MapKeys()[0]

    fmt.Println("KEY BEFORE", k)
    v1.SetMapIndex(k, reflect.Value{})  // COMMENT THIS OUT
    fmt.Println("m1:", m1)
    fmt.Println("KEY AFTER", k)

    v2 := reflect.ValueOf(m2)
    v2.SetMapIndex(k, reflect.Value{})
    fmt.Println("KEY AFTER SECOND CALL", k)
    fmt.Println("m2:", m2)
}

生成此输出:

map[a:true b:true]
KEY BEFORE a
m1: map[b:true]
KEY AFTER 
KEY AFTER SECOND CALL 
m2: map[a:true b:true]

请注意" a"值不会从m2中删除。注释掉指示的行会导致调用v2.SetMapIndex。

还要注意" k"的价值。调用SetMapIndex后更改。这似乎是SetMapIndex不起作用的原因。任何人都可以提供解释吗?这是一个错误吗?任何建议的解决方法?

感谢。

3 个答案:

答案 0 :(得分:0)

我认为这是一个错误? reflect.SetMapIndex的文档声明“如果val为零值,则SetMapIndex将从地图中删除密钥。”所以似乎正在发生的事情是关键是从反射类型下的地图中删除?值得注意的是,即使删除后,k仍然是string

fmt.Println(k.Kind())
fmt.Println(k.Len())

输出:

string
0

答案 1 :(得分:0)

我提交了一个错误:https://code.google.com/p/go/issues/detail?id=7896

它固定在提示中,但尚未传播到稳定版本。

此解决方法是构造代码,以便作为密钥源的地图是从中删除的最后一个地图。 (即,在原始帖子中反转对SetMapIndex()的调用将按预期运行。

答案 2 :(得分:-1)

SetMapIndex的调用将在删除操作期间触及完整的键/值对。

从概念的角度来看,这对我有意义。从地图中删除键/值对时,不应保证密钥保持不变。

不确定您要实现的目标,但可能会使用k2 := v2.MapKeys()[0]从地图v2中删除。但正如所建议的那样,不要对这样的事情使用反射。使用例如更好内置删除功能。

您还可以查看来源以了解原始详细信息:

http://golang.org/src/pkg/reflect/value.go

http://golang.org/src/pkg/runtime/hashmap.c

Some details on map internals