Отразить ошибку времени выполнения: вызов функцииlect.flag.mustBeAssignable при нулевом значении. - PullRequest
0 голосов
/ 19 января 2020

Я тестирую этот фрагмент кода на go детской площадке, я стремлюсь использовать отражение, чтобы получить поля от одного объекта, а затем установить значение для другого объекта

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.

Как это исправить?

Ответы [ 2 ]

2 голосов
/ 19 января 2020

Это как ошибка 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)
}
1 голос
/ 19 января 2020

Первый:

for i := 0; i < tt.NumField(); i++ {
    field := tt.Field(i)

Каждый шаг здесь перебирает поля вашего экземпляра типа T. Таким образом, поля будут A, а точнее - дескриптор поля, чей Name равен A и который описывает int с его json и тестовыми тегами, а затем B (с такими же подробными подробностями, если мы go далее).

Поскольку оба дескриптора поля имеют только два элемента Get, вы, вероятно, намеревались использовать Get("test"), как в ответ Гуарава Дхимана .

Однако, если вы сделаете это, результат будет "testaaa", когда вы находитесь в поле A и "testbbb", когда вы находитесь в поле B. Если мы аннотируем код Гуарава немного больше:

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}

Полная программа с закомментированной трассировкой здесь .

...