使用反射附加到lang切片

时间:2017-02-27 19:39:13

标签: go reflection

出于某种原因,似乎使用反射向切片添加新元素不会更新切片本身。这是演示的代码:

package main

import (
    "fmt"
    "reflect"
)

func appendToSlice(arrPtr interface{}) {
    valuePtr := reflect.ValueOf(arrPtr)
    value := valuePtr.Elem()
    value = reflect.Append(value, reflect.ValueOf(55))

    fmt.Println(value.Len()) // prints 1
}

func main() {
    arr := []int{}
    appendToSlice(&arr)
    fmt.Println(len(arr)) // prints 0
}

游乐场链接:https://play.golang.org/p/j3532H_mUL

这里有什么我想念的吗?

2 个答案:

答案 0 :(得分:9)

reflect.Append的作用类似append,因为它会返回一个新的切片值。

您要将此值分配给value函数中的appendToSlice变量,该变量将替换先前的reflect.Value,但不会更新原始参数。

为了更清楚地说明发生了什么,请将等效函数带到您的示例而不进行反射:

func appendToSlice(arrPtr *[]int) {
    value := *arrPtr
    value = append(value, 55)
    fmt.Println(len(value))
}

您需要使用的是Value.Set方法来更新原始值:

func appendToSlice(arrPtr interface{}) {
    valuePtr := reflect.ValueOf(arrPtr)
    value := valuePtr.Elem()

    value.Set(reflect.Append(value, reflect.ValueOf(55)))

    fmt.Println(value.Len())
}

https://play.golang.org/p/Nhabg31Sju

答案 1 :(得分:0)

    package main

    import "fmt"
    import "reflect"

    type Foo struct {
        Name string
    }

    func main() {
        _type := []Foo{}

        fmt.Printf("_type: v(%v) T(%T)\n", _type, _type)

        reflection := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(_type).Elem()), 0, 0)

        reflectionValue := reflect.New(reflection.Type())
        reflectionValue.Elem().Set(reflection)

        slicePtr := reflect.ValueOf(reflectionValue.Interface())

        sliceValuePtr := slicePtr.Elem()

        sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"a"})))
        sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"b"})))
        sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"c"})))

        values := []Foo{Foo{"d"}, Foo{"e"}}

        for _, val := range values {
            sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(val)))
        }

        result := sliceValuePtr.Interface()

        fmt.Printf("result: %T = (%v)\n", result, result)
    }

看看:https://play.golang.org/p/vXOqTVSEleO