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

I am trying to remove the same key from two maps using reflection. However, removing it from the first map is causing a change to the key value. Is this WAI or a bug.

Code at (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)
}

produces this output:

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

Notice that the "a" value is not removed from m2. Commenting out the indicated line causes the call to v2.SetMapIndex to work.

Also notice that the value of "k" changes after the call to SetMapIndex. That appears to be the reason that SetMapIndex isn't working. Can anyone offer an explanation? Is this a bug? Any suggested workaround?

Thanks.

I filed a bug: https://code.google.com/p/go/issues/detail?id=7896

It's fixed in the tip, but hasn't propagated out to the stable release.

The workaround for this is to structure the code so that the map which is the source of the key is the last map from which it's deleted. (I.e., reversing the calls to SetMapIndex() in the original post will behave as expected.

I think it's a bug? The documentation for reflect.SetMapIndex states that "If val is the zero Value, SetMapIndex deletes the key from the map." So it seems that what's happening is the key is getting deleted by the map out from under the reflection type? It's worth noting that even after the deletion, k is still a string:

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

Output:

string
0

The call to SetMapIndex will touch the complete key/value pair during the remove operation.

From a conceptual point of view this makes sense to me. When deleting a key/value pair from a map there shouldn't be a guarantee that the key stays intact.

Not sure what you are trying to achieve but might use k2 := v2.MapKeys()[0] to delete from map v2. But as suggested don't use reflections for things like this. It is far better to use e.g. the built in delete function.

You also might want to look at the sources to understand the raw details:

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

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

Some details on map internals