反映运行时错误:在零值上调用 reflect.flag.mustBeAssignable

我在去操场上测试这个代码片段,我的目标是使用反射从一个对象获取字段,然后将值设置为另一个对象


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.

如何解决?


梵蒂冈之花
浏览 227回答 2
2回答

料青山看我应如是

正如错误call of reflect.flag.mustBeAssignable on zero Value所说,newTValue.Elem().FieldByName(newTTag).CanSet()在您的代码中并根据文档返回 falseSet 将 x 分配给值 v。如果 CanSet 返回 false,它会发生混乱。与 Go 一样,x 的值必须可分配给 v 的类型。这是更正的代码,它从一个对象中获取字段并将值分配给另一个对象。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "reflect")type T struct {&nbsp; &nbsp; A int&nbsp; &nbsp; `json:"aaa" test:"AA"`&nbsp; &nbsp; B string `json:"bbb" test:"BB"`}type newT struct {&nbsp; &nbsp; AA int&nbsp; &nbsp; BB stringTestaaa string}func main() {&nbsp; &nbsp; t := T{&nbsp; &nbsp; &nbsp; &nbsp; A: 123,&nbsp; &nbsp; &nbsp; &nbsp; B: "hello",&nbsp; &nbsp; }&nbsp; &nbsp; tt := reflect.TypeOf(t)&nbsp; &nbsp; tv := reflect.ValueOf(t)&nbsp; &nbsp; newT := &newT{}&nbsp; &nbsp; newTValue := reflect.ValueOf(newT)&nbsp; &nbsp; for i := 0; i < tt.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; field := tt.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; newTTag := field.Tag.Get("test")&nbsp; &nbsp; &nbsp; &nbsp; tValue := tv.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; newTfield := newTValue.Elem().FieldByName(newTTag)&nbsp; &nbsp; &nbsp; &nbsp; if newTfield.CanSet() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;newTfield.Set(tValue)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(newT)}

慕码人8056858

第一的:for i := 0; i < tt.NumField(); i++ {&nbsp; &nbsp; field := tt.Field(i)这里的每一步都会遍历 type 实例的字段T。因此,这些字段将是A——或者更确切地说,是字段描述符,它的NameisA和它描述了一个带有 json 和 test 标记的 int ——然后B(如果我们再进一步,具有相同的挑剔细节)。由于两个字段描述符只有两个Get-able 项目,因此您可能打算使用Get("test"),如Guarav Dhiman 的回答。但是,如果你这样做,结果是"testaaa"你在场上A和"testbbb"场上的时候B。如果我们对 Guarav 的代码多加注解:for i := 0; i < tt.NumField(); i++ {&nbsp; &nbsp; field := tt.Field(i)&nbsp; &nbsp; newTTag := field.Tag.Get("test")&nbsp; &nbsp; fmt.Printf("newTTag = %#v\n", newTTag)&nbsp; &nbsp; tValue := tv.Field(i)&nbsp; &nbsp; newTfield := newTValue.Elem().FieldByName(newTTag)&nbsp; &nbsp; fmt.Printf("newTfield = %#v\n", newTfield)&nbsp; &nbsp; if newTfield.CanSet() {&nbsp; &nbsp; &nbsp; &nbsp; newTfield.Set(tValue)&nbsp; &nbsp; }}我们将看到这个输出:newTTag = "testaaa"newTfield = <invalid reflect.Value>newTTag = "testbbb"newTfield = <invalid reflect.Value>我们需要的是使test每个标签名称中的字符串成为类型中的字段newT:type T struct {&nbsp; &nbsp; A int&nbsp; &nbsp; `json:"aaa" test:"AA"`&nbsp; &nbsp; B string `json:"bbb" test:"BB"`}(Guarav 实际上已经这样做了,但没有提及。)现在程序产生了(大概)你想要的:&{123 hello}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go