Golang - создать объект того же типа, что и переданный - PullRequest
1 голос
/ 18 февраля 2020

Я пытаюсь создать обобщенную функцию c, которая будет анализировать ввод (в JSON) в указанную структуру. Структура может изменяться во время выполнения в зависимости от параметров, которые передаются в функцию. В настоящее время я пытаюсь добиться этого, передавая объект нужного типа и используя отражать.New () для создания нового выходного объекта того же типа.

Затем я анализирую JSON в этот объект и сканирование полей.

Если я создаю объект и указываю тип в коде, все работает. Если я передаю объект и пытаюсь создать реплику, я получаю «недопустимую косвенную» ошибку на несколько шагов ниже (см. Код).

import (
    "fmt"
    "reflect"
    "encoding/json"
    "strings"
)

type Test struct {
    FirstName   *string `json:"FirstName"`
    LastName    *string `json:"LastName"`
}

func genericParser(incomingData *strings.Reader, inputStructure interface{}) (interface{}, error) {
    //******* Use the line below and things work *******
    //parsedInput := new(Test)


    //******* Use vvv the line below and things don't work *******
    parsedInput := reflect.New(reflect.TypeOf(inputStructure))

    decoder := json.NewDecoder(incomingData)
    err := decoder.Decode(&parsedInput)
    if err != nil {
        //parsing error
        return nil, err
    }

    //******* This is the line that generates the error "invalid indirect of parsedInput (type reflect.Value)" *******
    contentValues := reflect.ValueOf(*parsedInput)
    for i := 0; i < contentValues.NumField(); i++ {
        //do stuff with each field
        fmt.Printf("Field name was: %s\n", reflect.TypeOf(parsedInput).Elem().Field(i).Name)
    }
    return parsedInput, nil
}


func main() {
    inputData := strings.NewReader("{\"FirstName\":\"John\", \"LastName\":\"Smith\"}")
    exampleObject := new(Test)
    processedData, err := genericParser(inputData, exampleObject)
    if err != nil {
        fmt.Println("Parsing error")
    } else {
        fmt.Printf("Success: %v", processedData)
    }
}

Если я не могу создать реплику объекта, тогда возможен способ обновления / возврата предоставленного. Ключевым моментом является то, что эта функция должна полностью соответствовать различным структурам.

1 Ответ

1 голос
/ 18 февраля 2020

reflect.New не является прямым аналогом new, так как он не может возвращать указанный тип c, он может возвращать только reflect.Value. Это означает, что вы пытаетесь разархивировать в *reflect.Value, что, очевидно, не сработает (даже если бы это произошло, ваш код был бы передан в **Type, что тоже не то, что вам нужно).

Используйте parsedInput.Interface(), чтобы получить базовое значение после создания нового значения, в которое нужно разобрать. Тогда вам не нужно отражать одно и то же значение во второй раз, поскольку это будет reflect.Value из reflect.Value, что опять-таки не даст ничего полезного.

Наконец, вы перед возвратом необходимо использовать parsedInput.Interface(), иначе вы возвращаете reflect.Value, а не значение типа ввода.

Например:

func genericParser(incomingData io.Reader, inputStructure interface{}) (interface{}, error) {
    parsedInput := reflect.New(reflect.TypeOf(inputStructure).Elem())

    decoder := json.NewDecoder(incomingData)
    err := decoder.Decode(parsedInput.Interface())
    if err != nil {
        return nil, err
    }

    for i := 0; i < parsedInput.Elem().NumField(); i++ {
        fmt.Printf("Field name was: %s\n", parsedInput.Type().Elem().Field(i).Name)
    }
    return parsedInput.Interface(), nil
}

https://play.golang.org/p/CzDrj6sgQNt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...