【问题标题】:Appending to a slice using reflection使用反射附加到切片
【发布时间】:2017-10-25 10:20:41
【问题描述】:

我想仅使用反射附加到切片。但我不知道如何用新切片“替换”a 的值。

func main() {
    fmt.Println("Hello, playground")

    a := []string {"a","b","c"}

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

    v := reflect.ValueOf(a)

    fmt.Printf("%t\n\n", v.Type())
    fmt.Printf("%t\n\n", v.Type().Elem().Kind())

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

    fmt.Printf("%t - %v", a, a)
}

此代码可在https://play.golang.org/p/cDlyH3jBDS 获取。

【问题讨论】:

    标签: go reflection slice


    【解决方案1】:

    如果包裹在reflect.Value 中的值源自非指针,则不能修改它。如果允许的话,你只能修改一个副本,会造成更多的混乱。切片值是包含指向后备数组的指针、长度和容量的标头。当您将a 传递给reflect.ValueOf() 时,会生成并传递此标头的副本,您可以对其进行的任何修改都只能修改此标头副本。原始切片标头不会观察到添加元素(并因此更改其长度以及可能的指针和容量),原始切片头仍将指向相同的数组,并且仍将包含相同的长度和容量值。详情见Are Golang function parameter passed as copy-on-write?;和Golang passing arrays to the function and modifying it

    你必须从一个指针开始,你可以使用Value.Elem() 来获取指向的、取消引用的值的reflect.Value 描述符。但是你必须从一个指针开始。

    更改代码中的这一行使其工作:

    v := reflect.ValueOf(&a).Elem()
    

    还要打印值的类型,请使用 %T 动词(%t 代表 bool 值):

    fmt.Printf("%T\n\n", v.Type())
    fmt.Printf("%T\n\n", v.Type().Elem().Kind())
    
    // ...
    
    fmt.Printf("%T - %v", a, a)
    

    输出(在Go Playground上试试):

    Hello, playground
    *reflect.rtype
    
    reflect.Kind
    
    []string - [a b c d e]
    

    如需更深入了解 Go 的反射,请阅读博文:The Laws of Reflection

    并阅读相关问题+答案:

    Assigning a value to struct member through reflection in Go

    Changing pointer type and value under interface with reflection

    Using reflection SetString

    【讨论】:

    • 这样说对吗,因为我没有将引用传递给reflect.ValueOf,所以我使用reflect.*执行的每个操作都应用于副本,因此无法修改原来的a?
    猜你喜欢
    • 2015-11-09
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 2016-10-20
    • 2017-09-22
    • 1970-01-01
    • 2016-05-25
    • 2019-01-02
    相关资源
    最近更新 更多