2

I want to reflect.New an []interface{} like []int and append it into another slice.

My code must have an error, but I don't know how to make it right and how to understand deeply the reflect.New and reflect.AppendSlice usage.

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var a []int
    var value reflect.Value = reflect.ValueOf(&a)


    if !value.CanSet() {
        fmt.Println("go here", value.CanSet())
        value = value.Elem() 
        fmt.Println("go here", value.CanSet())  
    }
    fmt.Println("go here", value.Type())    
    s := reflect.New(value.Type())
    fmt.Println("go here", s.Elem())
    value = reflect.AppendSlice(value, reflect.ValueOf(s.Elem()))
    value = reflect.AppendSlice(value, reflect.ValueOf([]int{1, 2}))                
    value = reflect.AppendSlice(value, reflect.ValueOf([]int{3, 4, 5, 6, 7, 8, 9})) 

    fmt.Println(value.Kind(), value.Slice(0, value.Len()).Interface())
    //>>slice [1 2 3 4 5 6 7 8 9]
}

But it gives an error:

panic: reflect: call of reflect.AppendSlice on struct Value

goroutine 1 [running]:
panic(0x100a60, 0x1040e1a0)
    /usr/local/go/src/runtime/panic.go:500 +0x720
reflect.flag.mustBe(0x99, 0x17)
    /usr/local/go/src/reflect/value.go:201 +0xe0
reflect.AppendSlice(0xfa7e0, 0x1040e130, 0x197, 0x1116a0, 0x1040e190, 0x99, 0x0, 0x0, 0x0, 0x2)
    /usr/local/go/src/reflect/value.go:1825 +0x60
main.main()
    /tmp/sandbox476529744/main.go:21 +0x800

golang playground

weizhao
  • 183
  • 3
  • 16
  • Main idea is the []int cannot be converted to []interface{}. There is no implicit conversion, therefore you cannot append such slice neither without reflect nor with. – lofcek Aug 28 '16 at 16:51
  • Thanks for your question, saving a lot time! – Chris Wong Oct 28 '20 at 08:55

3 Answers3

2

The panic is on this line:

value = reflect.AppendSlice(value, reflect.ValueOf(s.Elem()))

The value s.Elem() is a reflect.Value. Use this value directly in the call to AppendSlice:

value = reflect.AppendSlice(value, s.Elem())

The expression reflect.ValueOf(s.Elem()) returns the reflect.Value for a reflect.Value, not for the underlying []int.

playground example

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
1

Try this working sample ( The Go Playground ):

package main

import (
    "fmt"
    "reflect"
)

func main() {
    s := reflect.New(reflect.TypeOf([]interface{}{})).Elem()
    s = reflect.Append(s, reflect.ValueOf(1))
    s = reflect.AppendSlice(s, reflect.ValueOf([]interface{}{2, 3, 4, 5, 6, 7, 8, 9}))
    fmt.Println(s)
}

output:

[1 2 3 4 5 6 7 8 9]

And see: https://github.com/golang/go/wiki/InterfaceSlice :

The question then, "Why can't I assign any slice to an []interface{}, when I can assign any type to an interface{}?"

Why?

There are two main reasons for this.

The first is that a variable with type []interface{} is not an interface! It is a slice whose element type happens to be interface{}. But even given this, one might say that the meaning is clear.

Well, is it? A variable with type []interface{} has a specific memory layout, known at compile time.

Each interface{} takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type []interface{} is backed by a chunk of data that is N*2 words long.

This is different than the chunk of data backing a slice with type []MyType and the same length. Its chunk of data will be N*sizeof(MyType) words long.

The result is that you cannot quickly assign something of type []MyType to something of type []interface{}; the data behind them just look different.

0

Error in line 21:

value = reflect.AppendSlice(value, reflect.ValueOf(s.Elem()))

See doc:

func AppendSlice(s, t Value) Value
The slices s and t must have the same element type.

When you dump values, you see:

Var dump s.Elem(): []int(nil) 
Var dump reflect.ValueOf(s.Elem()): {typ:0xfa840 ptr:0x1040e160 flag:407} 
Var dump value: []int(nil) 

So you only need s.Elem()
See: https://play.golang.org/p/KwXRxGyswg

Son Bui
  • 301
  • 1
  • 5