如何使用反射将元素追加到切片作为映射值?

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

How to append to slices as map values with reflection?

问题

假设

  1. 我正在使用的是 go1.17 而不是 1.18,所以 go 1.18 的答案可能对其他人有帮助,但对我没有帮助。
  2. 我搜索并尝试了很多方法,但这种情况从未解决。

问题

import (
	"fmt"
	"reflect"
)

func main() {
	l := map[string][]interface{}{"a": {}}
	appendData(l["a"])
	fmt.Println(l["a"])
}

func appendData(k interface{}) {
	lValue := reflect.ValueOf(k)
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(1)))
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(2)))
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(3)))
}

我将场景简化为这段代码。我只需要能够从 appendData 函数中更改传递的接口切片([]interface{}) 的元素。请不要给我发送这行代码 l["a"] = appendData(l["a"]).([]interface{})。我知道这样可以工作,但由于某种原因我无法在我的代码中实现这一点(我正在做一些 BFS 的工作,我不能这样做,我必须一次更改一些值)。

我想要什么?

我只想看到这个输出:

[1, 2, 3]

这可能吗?还有其他替代的方法可以在代码的其他地方更改这些数据吗?谢谢你的帮助。

英文:

Assumptions

  1. I'm using go1.17 not 1.18 so answers in go 1.18 may help others but not me.
  2. I searched and tried many things but this scenario never solved.

Problem

import (
	"fmt"
	"reflect"
)

func main() {
	l := map[string][]interface{}{"a": {}}
	appendData(l["a"])
	fmt.Println(l["a"])
}

func appendData(k interface{}) {
	lValue := reflect.ValueOf(k)
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(1)))
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(2)))
	lValue.Set(reflect.Append(lValue, reflect.ValueOf(3)))
}

I simplified the scenario into this piece of code.
I just need to have the ability to change elements of that passed slice of interfaces([]interface{}) from appendData function.
Please do not send me this line of code l["a"] = appendData(l["a"]).([]interface{}).
I know that this works but I can't implement that in my code for some reason.(I'm doing some BFS stuff and I can't do this, I have to change some values at the time)

What I Want?

I just wanna see this output:

[1, 2, 3]

Is it possible?
Are there any other alternative ways that I can change those data from somewhere else in my code?
Thanks for your help.

答案1

得分: 4

你将永远不会看到[1, 2, 3]被打印出来,无论appendData()做了什么,只要传递了切片。

有两点需要注意:你不能更改存储在映射中的值。如果必须更改该值,你必须重新分配新值。详细信息请参见https://stackoverflow.com/questions/42716852/how-to-update-map-values-in-go/42716918#42716918

其次,你也不能更改存储在接口中的值。详细信息请参见https://stackoverflow.com/questions/47572782/removing-an-element-from-a-type-asserted-slice-of-interfaces/47572859#47572859

正确的方法是:如果你想要更改某些内容,总是传递一个指向它的指针,并修改指向的值。当然,在你的情况下,你不能传递指向存储在映射中的值的指针(即“指向映射的指针”),所以这是不可能的。映射索引表达式是不可寻址的,详细信息请参见https://stackoverflow.com/questions/57321933/cannot-take-the-address-of-map-element/57322003#57322003。如果你必须使用映射,你必须在映射中存储一个指针,并且可以传递该指针。

另一种方法是返回新的修改后的切片,并在调用者处分配新的切片,这正是内置的append()所做的(append()返回一个新的切片,你需要将其分配/存储)。如果你选择这种方法,你可以在映射中存储非指针切片,因为你可以将修改后的切片重新分配给相同的映射键。

英文:

You will never see [1, 2, 3] printed, no matter what appendData() does if only the slice is passed.

2 things: You can't change values stored in maps. If the value must be changed, you have to reassign the new value. For details see https://stackoverflow.com/questions/42716852/how-to-update-map-values-in-go/42716918#42716918

Second: you also can't change values stored in interfaces. For details, see https://stackoverflow.com/questions/47572782/removing-an-element-from-a-type-asserted-slice-of-interfaces/47572859#47572859

The right approach: if you want to change something, always pass a pointer to it, and modify the pointed value. Of course in your case you can't pass a pointer that points to a value stored in a map (that "points into the map"), so that's not possible. Map index expressions are not addressable, for details, see https://stackoverflow.com/questions/57321933/cannot-take-the-address-of-map-element/57322003#57322003. If you must use a map, you must store a pointer in the map, and you may pass that pointer.

Another approach is to return the new, modified slice and assign the new slice at the caller, exactly what / how the builtin append() does it (append() returns a new slice which you're expected to assign / store). If you go down this route, you may store non-pointer slices in the map, since you can reassign the modified slice to the same map key.

huangapple
  • 本文由 发表于 2022年6月1日 04:33:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/72453837.html
匿名

发表评论

匿名网友

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

确定