使用reflect,如何设置struct字段的值? [英] Using reflect, how do you set the value of a struct field?

查看:18
本文介绍了使用reflect,如何设置struct字段的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用 reflect 包处理结构体字段时遇到了困难.特别是,还没想好如何设置字段值.

<前>输入 t struct { fi int;fs 字符串 }var r t = t{ 123, "jblow" }var i64 int64 = 456

  1. 获取字段 i 的名称 - 这似乎有效

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

  2. 获取字段 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. 设置字段 i 的值 - 尝试一个 - 恐慌

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

    panic:reflect.Value·SetInt 使用未导出字段获得的值

    假设它不喜欢字段名称id"和name",所以重命名为Id"和Name"

    a) 这个假设正确吗?

    b) 如果正确,认为没有必要,因为在同一个文件/包中

  4. 设置字段 i 的值 - 尝试两个(字段名称大写) - 恐慌

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

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

    panic:reflect.Value·SetInt 使用不可寻址的值


@peterSO 下面的说明是全面和高质量的

四个.这有效:

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

他还记录了字段名称必须是可导出的(以大写字母开头)

解决方案

Go json 包在 Go 结构中编组和解组 JSON.

这是一个分步示例,它在小心避免错误的同时设置了 struct 字段的值.

Go reflect 包有一个 CanAddr 函数.

func (v Value) CanAddr() bool

<块引用>

如果值是地址可以通过Addr获取.这样的值称为可寻址的.一个值是可寻址的,如果它是切片的元素,一个元素可寻址数组,一个字段可寻址结构,或结果取消引用一个指针.如果可以地址返回 false,调用 Addr 会恐慌.

Go reflect 包有一个 CanSet 函数,如果 true,则意味着CanAddr 也是 true.

func (v Value) CanSet() bool

<块引用>

如果 v 的值,CanSet 返回真可以改变.可以更改值只有当它是可寻址的并且不是通过使用未出口的结构字段.如果 CanSet 返回false,调用 Set 或任何特定于类型的设置器(例如 SetBool、SetInt64) 会恐慌.

我们需要确保我们可以Set struct 字段.例如,

包主进口 (fm"反映")功能主(){输入 t 结构 {整数}无功n = t{42}//N 开始fmt.Println(n.N)//指向结构体的指针 - 可寻址ps :=reflect.ValueOf(&n)//结构体s := ps.Elem()如果 s.Kind() ==reflect.Struct {//导出字段f := s.FieldByName(N")如果 f.IsValid() {//一个值只有在它是时才能改变//可寻址但不是通过//使用未导出的结构字段.如果 f.CanSet() {//改变 N 的值如果 f.Kind() ==reflect.Int {x := int64(7)如果 !f.OverflowInt(x) {f.SetInt(x)}}}}}//N 在最后fmt.Println(n.N)}输出:427

如果我们可以确定所有的错误检查都是不必要的,那么这个例子就简化为,

包主进口 (fm"反映")功能主(){输入 t 结构 {整数}无功n = t{42}fmt.Println(n.N)reflect.ValueOf(&n).Elem().FieldByName(N").SetInt(7)fmt.Println(n.N)}

顺便说一句,Go 可作为开源代码.了解反射的一个好方法是了解核心 Go 开发人员如何使用它.例如,Go fmtjson 包.包文档在包文件标题下提供了指向源代码文件的链接.

having a rough time working with struct fields using reflect package. 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

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

  2. getting value of field i as a) interface{}, b) int - this seems to work

    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

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

    panic: reflect.Value·SetInt using value obtained using unexported field

    assuming it did not like field names "id" and "name", so renamed to "Id" and "Name"

    a) is this assumption correct?

    b) if correct, thought not necessary since in same file / package

  4. setting value of field i - try two (with field names capitalized ) - panic

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

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

    panic: reflect.Value·SetInt using unaddressable value


Instructions below by @peterSO are thorough and high quality

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.

Here's a step-by-step example which sets the value of a struct field while carefully avoiding errors.

The Go reflect package has a CanAddr function.

func (v Value) CanAddr() bool

CanAddr returns true if the value's address can be obtained with Addr. 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.

The Go reflect package has a CanSet function, which, if true, implies that CanAddr is also true.

func (v Value) CanSet() bool

CanSet returns true if the value of v can be changed. 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 (e.g., SetBool, SetInt64) will panic.

We need to make sure we can Set the struct field. 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. A good way to learn about reflection is to see how the core Go developers use it. For example, the Go fmt and json packages. The package documentation has links to the source code files under the heading Package files.

这篇关于使用reflect,如何设置struct字段的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆