使用reflect,如何设置struct字段的值?
技术问答
344 人阅读
|
0 人回复
|
2023-09-12
|
使用reflect包处理结构字段时遇到困难。特别是,我还没有考虑如何设置字段值。1 V7 o9 m8 l4 Y+ U' ^
输入 t struct { fi int; fs var rt = t{ 123,"jblow" }var i64 int64 = 456[ol]获取字段 i 的名称 - 这似乎有效[/ol]var field = reflect.TypeOf(r).Field(i).Name
! H& x! [/ a3 Y# D[ol]将字段 i 的值作为 a) interface{},b) int - 这似乎有效[/ol]var iface interface{} = reflect.ValueOf(r).Field(i).Interface()5 o' m' C1 e* ]4 T& ?
var i int = int(reflect.ValueOf(r).Field(i).Int())+ q! p. u4 T2 i+ k+ p
[ol]设置字段 i 的值 -尝试一个 - 恐慌[/ol]reflect.ValueOf(r).Field(i).SetInt( i64 )4 _$ T, Q; G" `% h* R. v+ h6 Y
恐慌:reflect.Value·SetInt 使用未导出字段获得的值6 O/ e8 u' p/ `4 @: I
假设它不喜欢字段名假设它不喜欢字段名id”和“name所以重命名为Id”和“Name”
. F' d4 s( @* {% h7 x. W- Ta) 这个假设正确吗?' n1 I! P( [4 r) r7 K: k q
b) 如果是正确的,认为没有必要,因为在同一个文件/包中
4 u3 X" F7 h: u[ol]设置字段 i 的值 - 尝试两个(字段名称大写) - 恐慌[/ol]reflect.ValueOf(r).Field(i).SetInt( 465 )& M" g$ x: s: F& Q
reflect.ValueOf(r).Field(i).SetInt( i64 )+ q5 h4 ^: H R, u
恐慌:reflect.Value·SetInt 使用不可寻址值
, D# W( u* o, J7 P' j@peterSO 以下描述全面、高质量% t. Y) k+ z# M
四、有效:
& Q9 g7 |! ~ e" a: r8 creflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )他还记录了字段名必须是可导出的(从大写字母开始): o, {% |" J0 q" |
- j* m: C; b U, N& Q8 K; y" M
解决方案: ! d8 v5 e, c+ V
Go json 包在 Go 结构中 JSON 编组和解组。
2 M- W+ d& B1 f1 O$ i3 }" I) o" C5 {这是一个分步示例struct设置字段值时要小心避免错误。
, m ^! o+ }) f, ]/ ]2 } k" z1 BGoreflect包有一个CanAddr功能。& l6 @* y0 n0 [. ?0 Q& T
func (v Value) CanAddr() bool; y* R* n6 G1 r5 V
如果可以使用 Addr 获取值的地址, CanAddr 返回 true。这样的值称为可寻址的。如果值是切片的元素、可寻址数组的元素、可寻址结构的字段或取消引用指针的结果,则该值是可寻址的。如果 CanAddr 返回 false,则调用 Addr 会导致恐慌。2 t/ g. V- q6 ~: z/ }
Goreflect包有一个CanSet函数,如果true,则意味着它CanAddr也是true。
% k; d! C) K1 S b9 R0 z8 z( [func (v Value) CanSet() bool
% O5 K) R+ J0 p; T) C9 p! v 如果可以改变 v , CanSet 返回 true。只有当值可以找到,而不是通过使用未导出的结构字段获得时,才能更改值。CanSet 返回 false,则调用 Set 或任何特定类型的 setter(例如 SetBool、SetInt64)恐慌会发生。
: X. c. a( d% C. b# ?: c我们需要确保我们能够Set在struct现场。例如,," k) ]( Q. M, p
package mainimport "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:427
- }: e F: _) F 假如我们能确定所有的错误检查都是不必要的,那么这个例子就简化为,
" A( Y" ~0 d# S8 U! ~5 i& f5 Qpackage mainimport "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)}# v5 @" G5 u" ?" ~( E
顺便说一句,Go 可用作开源代码。了解反射的好方法之一是了解核心 Go 开发人员如何使用它。例如,Go fmt和json包。包文件在包文件标题下提供指向源代码文件的链接。 |
|
|
|
|
|