英文:
How to append to slices as map values with reflection?
问题
假设
- 我正在使用的是 go1.17 而不是 1.18,所以 go 1.18 的答案可能对其他人有帮助,但对我没有帮助。
- 我搜索并尝试了很多方法,但这种情况从未解决。
问题
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
- I'm using go1.17 not 1.18 so answers in go 1.18 may help others but not me.
- 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论