Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set slice index using reflect in Go

I'm in Go, working with a reflect.Value representation of a slice. I have the following:

slice := reflect.MakeSlice(typ, len, cap)

If I want to get the ith value from slice, it's simple:

v := slice.Index(i) // returns a reflect.Value

However, I can't seem to find a way to set the ith value. reflect.Value has lots of setter methods, for example, if I had a map, m, the following is possible:

m.SetMapIndex(key, value) // key and value have type reflect.Value

But there doesn't seem to be an equivalent for slices. My one thought was that maybe the value returned from slice.Index(i) is actually a pointer somehow, so calling v := slice.Index(i); v.Set(newV) would work? I'm not sure. Ideas?

like image 770
joshlf Avatar asked Aug 07 '13 23:08

joshlf


2 Answers

Figured it out! Turns out I posted this prematurely - my guess that slice.Index(0) returns a pointer was correct. In particular:

one := reflect.ValueOf(int(1))

slice := reflect.MakeSlice(reflect.TypeOf([]int{}), 1, 1)
v := slice.Index(0)
fmt.Println(v.Interface())

v.Set(one)
fmt.Println(v.Interface())

v = slice.Index(0)
fmt.Println(v.Interface())

prints:

0
1
1

(Here's runnable code on the go playground)

like image 104
joshlf Avatar answered Nov 07 '22 10:11

joshlf


This might help:

n := val.Len()
if n >= val.Cap() {
    ncap := 2 * n
    if ncap < 4 {
        ncap = 4
    }
    nval := reflect.MakeSlice(val.Type(), n, ncap)
    reflect.Copy(nval, val)
    val.Set(nval)
}
val.SetLen(n + 1)
// ...
val.Index(n).SetString("value") // Depends on type

Taken from a library I wrote a while back github.com/webconnex/xmlutil, specifically decode.go.

like image 1
Luke Avatar answered Nov 07 '22 09:11

Luke