使用反射,你如何设置结构字段的值? [英] Using reflect, how do you set the value of a struct field?
问题描述
使用 reflect
包处理结构字段有一段艰难的时间。特别是,还没有想出如何设置字段值。
类型t结构{fi int; fs string}
var rt = t {123,jblow}
var i64 int64 = 456
- $
-
获取字段i的名称 - 这似乎工作
var field = reflect.TypeOf(r)。字段(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)
panic :reflect.Value· SetInt使用未使用未报告的字段获得的值
假定它不喜欢字段名称id和name,因此将其重命名为Id和Name
a)这个假设是否正确?b)如果正确,认为没有必要,因为在相同的文件/包中 -
settin g字段i的值 - 尝试两个(字段名大写) - 恐慌
$ p $ reflect $ value(r).Field(i).SetInt (465)
reflect.ValueOf(r).Field(i).SetInt(i64)$
$ bpanic :reflect.Value·SetInt using unaddressable value
getting Name of field i - this seems to work
var field = reflect.TypeOf(r).Field(i).Name
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())
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
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
ol>
下面的@peterSO说明是全面和高质量的
四。这样做:
他还记录了字段名称必须是可导出的(以大写字母开头) Go以开源代码。了解反思的一个好方法是看看核心Go开发人员如何使用它。例如,Go fmt 和 json 包。软件包文档包含指向Package文件标题下的源代码文件的链接。 Go json软件包编组并将JSON解组并封装到Go结构中。 b 这是一个循序渐进的例子,它设置 如果可以使用Addr获取值的 Go 如果可以更改v 我们需要确保我们可以 如果我们可以肯定所有的错误检查都是不必要的,那么这个例子简化为: reflect.ValueOf(& r).Elem()。Field(i).SetInt(i64)$ c
pre>
$ b $ p
$ b
struct
字段的值同时小心避免错误。
func(v Value)CanAddr()bool
地址,则CanAddr返回true 。
这些值称为可寻址的。如果
值是slice的
元素,
可寻址数组的元素,
可寻址结构的字段或$ b $的结果b解引用指针。如果CanAddr
返回false,调用Addr将导致
恐慌。
reflect
软件包有一个 CanSet
函数,如果 true
,意味着 CanAddr
也是 true
。
< pre $ func(v Value)CanSet()bool
的值,CanSet将返回true。只有在可寻址的情况下,Value才能被更改
,并且不能通过使用未导出的
struct字段获得
。如果CanSet返回
false,调用Set或任何
类型特定的setter(例如,SetBool,
SetInt64)将会出现混乱。
Set
struct
字段。例如,
包主
导入(
fmt
反映
)
func main(){
type t struct {
N int
}
var n = t {42 }
// N开始
fmt.Println(nN)
//结构指针 - 可寻址
ps:= reflect.ValueOf(& n)
//结构
s:= ps.Elem()$ b $如果s.Kind()== reflect.Struct {
//导出字段
f:= s.FieldByName(N )
如果f.IsValid(){
//一个值只有在
//可寻址时才能被更改,并且不能被
获得//使用未导出结构字段。
if f.CanSet(){
//改变N
的值如果f.Kind()== reflect.Int {
x:= int64(7)
如果!f.OverflowInt(x){
f.SetInt(x)
}
}
}
}
}
/ / N结束
fmt.Println(nN)
}
输出:
42
7
$ main(){
type t struct {
N int
}
var n = t {42}
fmt.PrintIn(nN)
反映。 ValueOf(& n).Elem()。FieldByName(N).SetInt(7)
fmt.Println(nN)
}
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
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)
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.
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)
}
这篇关于使用反射,你如何设置结构字段的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!