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