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

有一个粗略的时间使用结构字段使用反射包。特别是,还没有弄清楚如何设置字段值。
type t struct { fi int; fs string }
var r t = t{ 123,"jblow" }
var i64 int64 = 456

>获取字段名称i – 这似乎工作

var field = reflect.TypeOf(r).Field(i).Name
>获取字段i的值为a)interface {},b)int – 这似乎工作

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

var i int = int(reflect.ValueOf(r).Field(i).Int())
>字段i的设置值 – 尝试一个 – panic

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

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

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

a)这个假设是正确的吗?

b)如果正确,认为没有必要,因为在同一个文件/包
>设置字段i的值 – 尝试两个(字段名称大写) – panic

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是可用的 open source code.一个好的反思的方法是看看核心Go开发者如何使用它。例如,Go fmtjson包。软件包文档具有指向软件包文件标题下的源代码文件链接

Go json包将编组和解组JSON从和到Go结构。

这里是一个分步示例,设置结构字段的值,同时小心避免错误

Go reflect软件包具有CanAddr功能

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.

Go reflect软件包有一个CanSet函数,如果为真,意味着CanAddr也是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.

我们需要确保我们可以设置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)
}

相关文章

程序目录结构 简单实现,用户登录后返回一个jwt的token,下次请求带上token请求用户信息接口并返回信息...
本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简...
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其...
接下来学习并发编程, 并发编程是go语言最有特色的地方, go对并发编程是原生支持. goroutine是go中最近本...
先普及一下, 什么是广度优先搜索 广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶...
第一天: 接口的定义和实现 第二天: 一. go语言是面向接口编程. 在学习继承的时候说过, go语言只有封装,...