Home > Mobile >  How to append to slices as map values with reflection?
How to append to slices as map values with reflection?

Time:06-02

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.

CodePudding user response:

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 How to update map values in Go

Second: you also can't change values stored in interfaces. For details, see Removing an element from a type asserted Slice of interfaces

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 Cannot take the address of map element. 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.

  • Related