2

我想点赞并将其附加到另一个切片中reflect.New[]interface{}[]int

我的代码肯定有错误,但不知道如何改正,如何深入理解reflect.Newreflect.AppendSlice用法。

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]
}

但它给出了一个错误:

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

戈朗游乐场

4

3 回答 3

2

恐慌就在这一行:

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

值为s.Elem()a reflect.Value。直接在调用中使用此值AppendSlice

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

该表达式reflect.ValueOf(s.Elem())返回reflect.Valuea reflect.Value,而不是底层[]int

游乐场示例

于 2016-08-28T16:04:35.663 回答
1

试试这个工作示例(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)
}

输出:

[1 2 3 4 5 6 7 8 9]

请参阅:https ://github.com/golang/go/wiki/InterfaceSlice :

那么问题来了,“为什么我不能将任何切片分配给 []interface{},而我可以将任何类型分配给 interface{}?”

为什么?

这有两个主要原因。

首先是类型为 []interface{} 的变量不是接口!它是一个元素类型恰好是 interface{} 的切片。但即便如此,人们可能会说意思很清楚。

嗯,是吗?[]interface{} 类型的变量具有特定的内存布局,在编译时已知。

每个 interface{} 占用两个词(一个词表示所包含内容的类型,另一个词表示包含的数据或指向它的指针)。因此,长度为 N 且类型为 []interface{} 的切片由 N*2 个字长的数据块支持。

这与支持具有 []MyType 类型和相同长度的切片的数据块不同。它的数据块将是 N*sizeof(MyType) 个字长。

结果是您不能快速将 []MyType 类型的东西分配给 []interface{} 类型的东西;他们背后的数据看起来不同。

于 2016-08-28T18:07:26.617 回答
0

第 21 行错误:

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

见文档:

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

当您转储值时,您会看到:

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

所以你只需要s.Elem()
查看: https: //play.golang.org/p/KwXRxGyswg

于 2016-08-28T16:22:07.683 回答