简体   繁体   English

使用reflect,如何设置struct字段的值?

[英]Using reflect, how do you set the value of a struct field?

having a rough time working with struct fields using reflect package.使用reflect包处理结构字段时遇到了困难。 in particular, have not figured out how to set the field value.特别是,还没想好如何设置字段值。

type t struct { fi int; fs string }
var r t = t{ 123, "jblow" }
var i64 int64 = 456
  1. getting Name of field i - this seems to work获取字段 i 的名称 - 这似乎有效

    var field = reflect.TypeOf(r).Field(i).Name

  2. getting value of field i as a) interface{}, b) int - this seems to work将字段 i 的值作为 a) interface{}, b) int - 这似乎有效

    var iface interface{} = reflect.ValueOf(r).Field(i).Interface()

    var i int = int(reflect.ValueOf(r).Field(i).Int())

  3. setting value of field i - try one - panic设置字段 i 的值 - 尝试一个 - 恐慌

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    panic : reflect.Value·SetInt using value obtained using unexported field panic : reflect.Value·SetInt 使用使用未导出字段获得的值

    assuming it did not like field names "id" and "name", so renamed to "Id" and "Name"假设它不喜欢字段名称“id”和“name”,所以重命名为“Id”和“Name”

    a) is this assumption correct? a) 这个假设正确吗?

    b) if correct, thought not necessary since in same file / package b) 如果正确,认为没有必要,因为在同一个文件/包中

  4. setting value of field i - try two (with field names capitalized ) - panic设置字段 i 的值 - 尝试两个(字段名称大写) - 恐慌

    reflect.ValueOf(r).Field(i).SetInt( 465 )

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    panic : reflect.Value·SetInt using unaddressable value恐慌:reflect.Value·SetInt 使用不可寻址的值


Instructions below by @peterSO are thorough and high quality @peterSO 下面的说明是全面和高质量的

Four.四。 this works:这有效:

reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )

he documents as well that the field names must be exportable (begin with capital letter)他还记录了字段名称必须是可导出的(以大写字母开头)

The Go json package marshals and unmarshals JSON from and to Go structures. Go json 包对 Go 结构中的 JSON 进行编组和解组。

Here's a step-by-step example which sets the value of a struct field while carefully avoiding errors.这是一个分步示例,它设置struct字段的值,同时小心地避免错误。

The Go reflect package has a CanAddr function. Go reflect包有一个CanAddr函数。

func (v Value) CanAddr() bool

CanAddr returns true if the value's address can be obtained with Addr.如果可以使用 Addr 获取值的地址,则 CanAddr 返回 true。 Such values are called addressable.这样的值称为可寻址的。 A value is addressable if it is an element of a slice, an element of an addressable array, a field of an addressable struct, or the result of dereferencing a pointer.如果值是切片的元素、可寻址数组的元素、可寻址结构的字段或取消引用指针的结果,则该值是可寻址的。 If CanAddr returns false, calling Addr will panic.如果 CanAddr 返回 false,则调用 Addr 将导致恐慌。

The Go reflect package has a CanSet function, which, if true , implies that CanAddr is also true . Go reflect包有一个CanSet函数,如果为true ,则意味着CanAddr也是true

func (v Value) CanSet() bool

CanSet returns true if the value of v can be changed.如果 v 的值可以更改,则 CanSet 返回 true。 A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields.只有当值可寻址且不是通过使用未导出的结构字段获得时,才可以更改值。 If CanSet returns false, calling Set or any type-specific setter (eg, SetBool, SetInt64) will panic.如果 CanSet 返回 false,则调用 Set 或任何特定于类型的 setter(例如 SetBool、SetInt64)将发生恐慌。

We need to make sure we can Set the struct field.我们需要确保我们可以Set struct字段。 For example,例如,

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    // N at start
    fmt.Println(n.N)
    // pointer to struct - addressable
    ps := reflect.ValueOf(&n)
    // struct
    s := ps.Elem()
    if s.Kind() == reflect.Struct {
        // exported field
        f := s.FieldByName("N")
        if f.IsValid() {
            // A Value can be changed only if it is 
            // addressable and was not obtained by 
            // the use of unexported struct fields.
            if f.CanSet() {
                // change value of N
                if f.Kind() == reflect.Int {
                    x := int64(7)
                    if !f.OverflowInt(x) {
                        f.SetInt(x)
                    }
                }
            }
        }
    }
    // N at end
    fmt.Println(n.N)
}

Output:
42
7

If we can be certain that all the error checks are unnecessary, the example simplifies to,如果我们可以确定所有错误检查都是不必要的,则示例简化为,

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    fmt.Println(n.N)
    reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
    fmt.Println(n.N)
}

BTW , Go is available as open source code .顺便说一句,Go 可以作为开源代码使用 A good way to learn about reflection is to see how the core Go developers use it.了解反射的一个好方法是了解核心 Go 开发人员如何使用它。 For example, the Go fmt and json packages.例如,Go fmtjson包。 The package documentation has links to the source code files under the heading Package files.包文档在包文件标题下提供了指向源代码文件的链接。

This seems to work:这似乎有效:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    Number int
    Text string
}

func main() {
    foo := Foo{123, "Hello"}

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))

    reflect.ValueOf(&foo).Elem().Field(0).SetInt(321)

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
}

Prints:印刷:

123
321

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM