簡體   English   中英

反映運行時錯誤:在零值上調用reflect.flag.mustBeAssignable

[英]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錯誤call of reflect.flag.mustBeAssignable on zero Value說, newTValue.Elem().FieldByName(newTTag).CanSet()在您的代碼中並根據文檔返回 false

Set 將 x 分配給值 v。如果 CanSet 返回 false,它會發生恐慌。 在 Go 中,x 的值必須可以分配給 v 的類型。

這是從一個對象中獲取字段並將值分配給另一個對象的更正代碼。

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 -或者更確切地說,現場描述,其NameA ,並描述其JSON和測試代碼,然后一個int B (具有相同的挑剔細節,如果我們再往前走)。

由於兩個字段描述符都只有兩個Get able 項,因此您可能打算使用Get("test") ,如Guarav Dhiman 的 answer

如果你這樣做,不過,結果是"testaaa"當你在野外A"testbbb"當你在野外的B 如果我們多注釋 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"`
}

(瓜拉夫實際上已經這樣做了,但沒有提到它。)現在程序產生了(大概)你想要的:

&{123 hello}

帶有注釋掉跟蹤的完整程序在這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM