当前位置: 首页 > 面试题库 >

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

柴俊捷
2023-03-14
问题内容

在使用reflect包处理结构字段时遇到了麻烦。特别是,还没有弄清楚如何设置字段值。

输入t struct {fi int; fs字符串}
var rt = t {123,“ jblow”}
var i64 int64 = 456
  1. 获取字段i的名称-这似乎起作用

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

  1. 作为a)接口{},b)int获取字段i的值-这似乎有效

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

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

  1. 设置字段i的值-尝试一次-紧急

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

恐慌 :使用未导出字段中获得的值,使用reflect.Value·SetInt

假设它不喜欢字段名称“ id”和“ name”,因此将其重命名为“ Id”和“ Name”

a)这个假设正确吗?

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

  1. 设置字段i的值-尝试两个(字段名大写)-紧急

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

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

恐慌 :使用不可寻址的值反映。

@peterSO的以下说明全面,高质量

四。这有效:

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

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


问题答案:

Go是开放源代码。了解反射的一个好方法是查看核心Go开发人员如何使用它。例如,Go
fmt和json包。软件包文档在“软件包文件”标题下具有指向源代码文件的链接。

Go json程序包将JSON从Go结构中封送和解组。

这是一个分步示例,它struct在谨慎地避免错误的同时设置字段的值。

Go
reflect软件包具有一个CanAddr功能

func (v Value) CanAddr() bool

如果可以通过Addr获取值的地址,则CanAddr返回true。这样的值称为可寻址的。如果值是切片的元素,可寻址数组的元素,可寻址结构的字段或取消引用指针的结果,则该值是可寻址的。如果CanAddr返回false,则调用Addr会惊慌。

Go
reflect程序包具有一个CanSet函数,如果有的话true,意味着它CanAddr也为true

func (v Value) CanSet() bool

如果v的值可以更改,则CanSet返回true。值只能是可寻址的,并且不是通过使用未导出的结构字段获得的,才可以更改。如果CanSet返回false,则调用Set或任何特定于类型的setter(例如SetBool,SetInt64)都会感到恐慌。

我们需要确保我们能做到Set这一点struct。例如,

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

如果可以确定所有错误检查都是不必要的,则该示例将简化为:

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


 类似资料:
  • 问题内容: 有什么方法可以使用反射设置界面字段?当我尝试设置它时,它惊慌地说该值不可寻址。 问题答案: 接口没有字段,它们仅定义包含的值的方法集。在界面上进行反射时,可以使用提取值。 您也不能取消导出字段。您需要大写您的类型的字段名称。遍历字段时,用于测试它们是否可设置。如果该值不可寻址或该值仍在接口中,则也会返回false。 您的代码的有效示例:http : //play.golang.org/

  • 问题内容: 这段代码: 印刷品: 没有实现,因此它不是a 并打印其本机表示形式。但是对于我要打印的每个结构都非常繁琐。更糟糕的是,如果添加或删除某些字段,则必须更新。有没有更简单的方法来打印带有其字段的结构的结构? 问题答案: 这就是该包的实现方式,因此您无法更改。 但是,您可以编写一个使用反射(包)来遍历struct的字段的辅助函数,并可以在具有此类方法的字段上调用该方法。 示例实现: 现在,当

  • 问题内容: 我正在与一个非开源项目合作,我需要修改一个或多个其类。 在一个类中是以下集合: 我需要做的就是在这里使用反射和并发hashmap。我试过下面的代码,但是不起作用。 问题答案: 希望这是您要尝试做的事情: 它打印:

  • 我使用的是registfit的新beta版本(2.0.0-beta),我使用registfit-gson-converter创建一个POJO。 当使用GSON和改型时,这可能吗?

  • 我正在使用react并使用Ant DesignV4.1.0。 我有一个表单,在提交(onFinish)时,我将id发送给reducer以获得字段的所有值。我这样做是因为我的要求(我必须选择表单本身的id并多次获取所有数据,还必须用特定的id从多个地方打开相同的表单)。也许有更好的方法来达到我的要求,但目前我正在这样做。 我正在获得所需的数据道具(我验证了),但我不能用新道具更新字段。 我已经设置好

  • 问题内容: 如果我将类型定义为: 那我该如何克隆这种类型的对象呢?如果我做一个简单的任务: 然后,对受影响的两个对象所做的任何更改。由于未导出,因此即使使用反射提取,也无法显式复制。 我目前在类型本身的包中提供一个方法。但这对其他软件包中的类似类型没有帮助。还有另一种方法吗? 问题答案: 你不能 这就是未导出字段的意义:只有声明包才能修改它们。 请注意,如果在另一个包中声明了该类型,则您甚至无法编