使用 reflect
包处理结构字段时遇到了困难。特别是,还没弄清楚如何设置字段值。
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 的设置值 - 尝试一个 - 恐慌反映.ValueOf(r).Field(i).SetInt(i64) 恐慌:reflect.Value·SetInt 使用使用未导出字段获得的值假设它不喜欢字段名称“id”和“name”,因此重命名为“Id”和“名称” a) 这个假设正确吗? b) 如果正确,则认为没有必要,因为在同一文件/包中设置字段 i 的值 - 尝试两个(字段名称大写) - 恐慌 reflect.ValueOf(r).Field(i).SetInt( 465 ) reflect.ValueOf( r).Field(i).SetInt(i64) 恐慌:reflect.Value·SetInt 使用不可寻址的值
@peterSO 下面的说明是彻底和高质量的
四。这有效:
reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )
他还记录了字段名称必须是可导出的(以大写字母开头)
reflect
设置数据的人,我能找到的最接近的示例是 comments.gmane.org/gmane.comp.lang.go.general/35045,但即使在那里,他也使用 json.Unmarshal
来完成实际的脏活
Go json 包从 Go 结构中编组和解组 JSON。
这是一个分步示例,它设置 struct
字段的值,同时小心避免错误。
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 或任何特定类型的设置器(例如,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)
}
顺便说一句,Go 可用作 open source code。了解反射的一个好方法是看看核心 Go 开发人员如何使用它。例如,Go fmt 和 json 包。包文档在标题包文件下有指向源代码文件的链接。
这似乎有效:
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()))
}
印刷:
123
321
不定期副业成功案例分享