reflect runtime error: call of reflect.flag.mustBeAssignable on zero Value
reflect runtime error: call of reflect.flag.mustBeAssignable on zero Value
我正在 go playground 上测试这段代码片段,我的目标是使用反射从一个对象获取字段,然后将值设置为另一个对象
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"testaaa"`
B string `json:"bbb" test:"testbbb"`
}
type newT struct {
AA int
BB string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("newT")
tValue := tv.Field(i)
newTValue.Elem().FieldByName(newTTag).Set(tValue)
}
fmt.Println(newT)
}
它给出了一个非常奇怪的错误:
panic: reflect: call of reflect.flag.mustBeAssignable on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x0, 0x0)
/usr/local/go/src/reflect/value.go:240 +0xe0
reflect.flag.mustBeAssignable(...)
/usr/local/go/src/reflect/value.go:234
reflect.Value.Set(0x0, 0x0, 0x0, 0x100f80, 0x40a0f0, 0x82)
/usr/local/go/src/reflect/value.go:1531 +0x40
main.main()
/tmp/sandbox166479609/prog.go:32 +0x400
Program exited: status 2.
如何解决?
如错误 call of reflect.flag.mustBeAssignable on zero Value
所述,您的代码中 newTValue.Elem().FieldByName(newTTag).CanSet()
returns 错误
Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.
这是更正的代码,它从一个对象中获取字段并将值分配给另一个对象。
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
type newT struct {
AA int
BB string
Testaaa string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
fmt.Println(newT)
}
第一个:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
此处的每个步骤都遍历类型 T
实例的字段。所以字段将是 A
——或者更确切地说,字段描述符 Name
是 A
,它描述了一个带有 json 和测试标签的整数——然后是 B
(如果我们更进一步,也会有同样挑剔的细节)。
由于两个字段描述符只有两个 Get
-able 项目,您可能打算使用 Get("test")
,如 .
但是,如果你这样做,当你在场 A
时,结果是 "testaaa"
,当你在场 B
时,结果是 "testbbb"
。如果我们对 Guarav 的代码多加一点注释:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
fmt.Printf("newTTag = %#v\n", newTTag)
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
fmt.Printf("newTfield = %#v\n", newTfield)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
我们将看到这个输出:
newTTag = "testaaa"
newTfield = <invalid reflect.Value>
newTTag = "testbbb"
newTfield = <invalid reflect.Value>
我们需要的是让每个标签名称中的test
字符串成为newT
类型中的字段:
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
(Guarav 实际上已经这样做了,但没有提及。)现在程序产生了(大概)您想要的结果:
&{123 hello}
带有注释掉跟踪的完整程序是 here。
我正在 go playground 上测试这段代码片段,我的目标是使用反射从一个对象获取字段,然后将值设置为另一个对象
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"testaaa"`
B string `json:"bbb" test:"testbbb"`
}
type newT struct {
AA int
BB string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("newT")
tValue := tv.Field(i)
newTValue.Elem().FieldByName(newTTag).Set(tValue)
}
fmt.Println(newT)
}
它给出了一个非常奇怪的错误:
panic: reflect: call of reflect.flag.mustBeAssignable on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x0, 0x0)
/usr/local/go/src/reflect/value.go:240 +0xe0
reflect.flag.mustBeAssignable(...)
/usr/local/go/src/reflect/value.go:234
reflect.Value.Set(0x0, 0x0, 0x0, 0x100f80, 0x40a0f0, 0x82)
/usr/local/go/src/reflect/value.go:1531 +0x40
main.main()
/tmp/sandbox166479609/prog.go:32 +0x400
Program exited: status 2.
如何解决?
如错误 call of reflect.flag.mustBeAssignable on zero Value
所述,您的代码中 newTValue.Elem().FieldByName(newTTag).CanSet()
returns 错误
Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.
这是更正的代码,它从一个对象中获取字段并将值分配给另一个对象。
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
type newT struct {
AA int
BB string
Testaaa string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
fmt.Println(newT)
}
第一个:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
此处的每个步骤都遍历类型 T
实例的字段。所以字段将是 A
——或者更确切地说,字段描述符 Name
是 A
,它描述了一个带有 json 和测试标签的整数——然后是 B
(如果我们更进一步,也会有同样挑剔的细节)。
由于两个字段描述符只有两个 Get
-able 项目,您可能打算使用 Get("test")
,如
但是,如果你这样做,当你在场 A
时,结果是 "testaaa"
,当你在场 B
时,结果是 "testbbb"
。如果我们对 Guarav 的代码多加一点注释:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
fmt.Printf("newTTag = %#v\n", newTTag)
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
fmt.Printf("newTfield = %#v\n", newTfield)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
我们将看到这个输出:
newTTag = "testaaa"
newTfield = <invalid reflect.Value>
newTTag = "testbbb"
newTfield = <invalid reflect.Value>
我们需要的是让每个标签名称中的test
字符串成为newT
类型中的字段:
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
(Guarav 实际上已经这样做了,但没有提及。)现在程序产生了(大概)您想要的结果:
&{123 hello}
带有注释掉跟踪的完整程序是 here。