使用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)接口{},b)int - 这似乎有用
var iface interface{} = reflect.ValueOf(r).Field(i).Interface()
var i int = int(reflect.ValueOf(r).Field(i).Int())
设置字段i的值 - 尝试一个 - 恐慌
reflect.ValueOf(r).Field(i).SetInt( i64 )
恐慌:reflect.Value·使用未导出字段获取的值的SetInt
假设它不喜欢字段名称“id”和“name”,所以重命名为“Id”和“Name”
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 )
他还记录了字段名称必须是可导出的(以大写字母开头)
答案 0 :(得分:125)
Go以open source code的形式提供。了解反射的一个好方法是看看核心Go开发人员如何使用它。例如,Go fmt和json包。包文档包含指向包文件下的源代码文件的链接。
Go json包编组并从Go结构中解组JSON。
这是一个循序渐进的示例,它设置struct
字段的值,同时小心避免错误。
func (v Value) CanAddr() bool
如果值为,则CanAddr返回true 地址可以用Addr获得。 这些值称为可寻址。一个 如果是值,则值是可寻址的 切片的元素,元素的元素 可寻址数组,一个字段 可寻址结构,或结果 取消引用指针。如果CanAddr 返回false,调用Addr会 恐慌。
Go reflect
包具有CanSet
功能,如果true
,则表示CanAddr
也是true
。
func (v Value) CanSet() bool
如果v的值,CanSet返回true 可以改变。值可以更改 只有它是可寻址的而不是 通过使用未经报告获得 结构字段。如果CanSet返回 false,调用Set或any 特定于类型的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)
}
答案 1 :(得分:11)
这似乎有效:
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