使用反射从映射中删除键是否会改变键本身?这是一个错误吗?

huangapple go评论111阅读模式
英文:

Removing key from map using reflection changes key? Is this a bug?

问题

我正在尝试使用反射从两个映射中删除相同的键。然而,从第一个映射中删除它会导致键值发生变化。这是正常行为还是一个错误?

代码链接:http://play.golang.org/p/MIkFP_Zrxb

请注意输出结果:

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

注意到在m2中,"a"的值没有被删除。注释掉所示行会使v2.SetMapIndex的调用起作用。

还请注意,在调用SetMapIndex之后,"k"的值发生了变化。这似乎是SetMapIndex无法正常工作的原因。有人能解释一下吗?这是一个错误吗?有什么建议的解决方法吗?

谢谢。

英文:

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.

答案1

得分: 0

我认为这是一个 bug?reflect.SetMapIndex 的文档中指出:“如果 val 是零值,SetMapIndex 会从 map 中删除该键。”所以看起来发生的情况是在反射类型下,键被从 map 中删除了?值得注意的是,即使在删除后,k 仍然是一个 string 类型:

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

输出:

string
0
英文:

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

答案2

得分: 0

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

这个问题在最新版本中已经修复,但还没有传播到稳定版本。

解决这个问题的方法是将代码结构化,使得作为键源的映射是最后一个被删除的映射。(即,将原始帖子中的SetMapIndex()调用顺序反转将会按预期运行。)

英文:

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.

答案3

得分: -1

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

从概念上讲,这对我来说是有意义的。从映射中删除键/值对时,并不能保证键保持不变。

不确定你想要实现什么,但可以使用k2 := v2.MapKeys()[0]从映射v2中删除。但是,正如建议的那样,不要使用反射来处理此类事情。最好使用内置的delete函数。

你也可以查看源代码以了解原始细节:

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

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

关于映射内部的一些细节

英文:

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

huangapple
  • 本文由 发表于 2014年4月30日 02:06:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/23372096.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定