Создать гетерогенный массив JSON в Go - PullRequest
0 голосов
/ 19 ноября 2018

Предположим, у меня есть такая структура в go:

type Message struct {
    Args   []interface{}
    Kwargs map[string]interface{}
}

message := Message{                                                                                                                                                                                            
    []interface{}{1, 2, 3, 4},                                                                                                                                                                                 
    map[string]interface{}{"a": 2, "b": 3},                                                                                                                                                                    
}

Как мне маршалировать сообщение, чтобы иметь такой JSON?

[[1,2,3,4], {"a": 2, "b":3}]

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вы можете добавить маршальный метод в вашу структуру для обработки логики. Что-то в строках

func (m Message) MarshalJSON() ([]byte, error) {
    data := make([]interface{}, 0)
    data = append(data, m.Args)
    data = append(data, m.Kwargs)
    return json.Marshal(data)
}

Попробуйте на детской площадке

0 голосов
/ 19 ноября 2018

В выводе требуется массив JSON, содержащий поля Args и Kwargs вашего значения структуры message, так что вы можете получить то, что хотите, маршируя следующее значение среза:

[]interface{}{message.Args, message.Kwargs}

Например:

message := Message{
    []interface{}{1, 2, 3, 4},
    map[string]interface{}{"a": 2, "b": 3},
}

err := json.NewEncoder(os.Stdout).
    Encode([]interface{}{message.Args, message.Kwargs})

fmt.Println(err)

Вывод вышеизложенного (попробуйте на Go Playground ):

[[1,2,3,4],{"a":2,"b":3}]
<nil>

Это работает для этого конкретного случая. Если вам нужно общее решение, которое собирает поля со структурным значением, например, элементы массива, вы можете создать вспомогательную функцию, которая «упаковывает» поля в срез:

func getFields(i interface{}) (res []interface{}) {
    v := reflect.ValueOf(i)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }
    if v.Kind() != reflect.Struct {
        return nil
    }

    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        if f.CanInterface() {
            res = append(res, f.Interface())
        }
    }
    return res
}

Выше getFields() принимает значения структуры и указатели на структуры. Пример использования его:

message := Message{
    []interface{}{1, 2, 3, 4},
    map[string]interface{}{"a": 2, "b": 3},
}

err := json.NewEncoder(os.Stdout).Encode(getFields(message))
fmt.Println(err)

err = json.NewEncoder(os.Stdout).Encode(getFields(&message))
fmt.Println(err)

Вывод (попробуйте на Go Playground ):

[[1,2,3,4],{"a":2,"b":3}]
<nil>
[[1,2,3,4],{"a":2,"b":3}]
<nil>
...