Преобразовать структуру в структуру среза - PullRequest
0 голосов
/ 25 мая 2020

Я пытаюсь выбрать структуру с помощью строкового ввода, а затем, в зависимости от возвращаемого JSON объекта или массива, разупорядочить JSON. Правильно ли думать о способе отражения структуры в структуру среза? если да, то как это сделать с отражением? С уважением, Петр

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
)

type NameStruct struct {
    Name string
}

func main() {

    jsonData := []byte(`[{"name":"james"},{"name":"steven"}]`)
    returnModel := InitializeModel("NameStruct", jsonData)
    fmt.Println(returnModel)

    jsonData = []byte(`{"name":"james"}`)
    returnModel = InitializeModel("NameStruct", jsonData)
    fmt.Println(returnModel)

}

func getModelByName(modelType string) interface{} {
    modelMap := make(map[string]interface{})
    modelMap["NameStruct"] = new(NameStruct)

    //don't want to do this
    modelMap["arrNameStruct"] = new([]NameStruct)
    return modelMap[modelType]
}

func InitializeModel(modelName string, jsonData []byte) interface{} {
    switch IsArray(jsonData) {
    case true:
        // some conversion here, how?
        returnModel := getModelByName("NameStruct")
        if err := json.Unmarshal(jsonData, &returnModel); err != nil {
            log.Println(err)
        }
        return returnModel
    case false:
        returnModel := getModelByName("NameStruct")
        if err := json.Unmarshal(jsonData, &returnModel); err != nil {
            log.Println(err)
        }
        return returnModel
    }
    return nil
}

func IsArray(jsonData []byte) bool {
    return (bytes.HasPrefix(jsonData, []byte("["))) && (bytes.HasSuffix(jsonData, []byte("]")))
}

1 Ответ

1 голос
/ 25 мая 2020

Расширяя мой комментарий, вы можете создать Factory, в котором зарегистрированы предопределенные типы:

type Factory struct {
    m map[string]reflect.Type
}

func (f *Factory) Register(v interface{}) {
    vt := reflect.TypeOf(v)
    n := vt.Name()
    f.m[n] = vt
    f.m["[]"+n] = reflect.SliceOf(vt) // implicitly register a slice of type too
}

эти типы можно искать по имени во время выполнения и инициализировать данными JSON:

func (f *Factory) Make(k string, bs []byte) (interface{}, error) {
    vt, ok := f.m[k]
    if !ok {
        return nil, fmt.Errorf("type %q not registered", k)
    }

    pv := reflect.New(vt).Interface()

    err := json.Unmarshal(bs, pv)
    if err != nil {
        return nil, err
    }

    return pv, nil
}

Для использования:

type Place struct {
    City string `json:"city"`
}

factory.Register(Place{})

p, err := factory.Make("Place", []byte(`{"city":"NYC"}`))

fmt.Printf("%#v\n", p) // &main.Place{City:"NYC"}

Ломтики тоже работают:

ps, err := factory.Make("[]Place", []byte(`[{"city":"NYC"},{"city":"Dublin"}]`))

fmt.Printf("%#v\n", p, p) // &[]main.Place{main.Place{City:"NYC"}, main.Place{City:"Dublin"}}

Детская площадка: https://play.golang.org/p/qWEdwk-YUug

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