Функция преобразования структуры в карту в Голанге

Я хочу преобразовать структуру в карту в Голанге. Было бы неплохо, если бы я мог использовать теги JSON как ключи в созданной карте (в противном случае по умолчанию было бы имя поля).

Редактировать TL; версия DR, 15 июня 2015 г.

Если вы хотите, чтобы быстрое решение для преобразования структуры в карту, см. принятый ответ, увеличьте его и используйте этот пакет.

Счастливое кодирование!:)


Оригинальное сообщение

Пока у меня есть эта функция, я использую пакет отражения, но я не понимаю, как использовать пакет, пожалуйста, не стесняйтесь.

func ConvertToMap(model interface{}) bson.M {
    ret := bson.M{}

    modelReflect := reflect.ValueOf(model)

    if modelReflect.Kind() == reflect.Ptr {
        modelReflect = modelReflect.Elem()
    }

    modelRefType := modelReflect.Type()
    fieldsCount := modelReflect.NumField()

    var fieldData interface{}

    for i := 0; i < fieldsCount; i++ {
        field := modelReflect.Field(i)

        switch field.Kind() {
        case reflect.Struct:
            fallthrough
        case reflect.Ptr:
            fieldData = ConvertToMap(field.Interface())
        default:
            fieldData = field.Interface()
        }

        ret[modelRefType.Field(i).Name] = fieldData
    }

    return ret
}

Также я посмотрел исходный код пакета JSON, потому что он должен содержать мою нужную реализацию (или ее части), но не слишком много понимает.

Ответ 1

Мне также нужно было что-то вроде этого. Я использовал внутренний пакет, который преобразовывал структуру в карту. Я решил открыть его с помощью других функций высокого уровня struct. Посмотрите:

https://github.com/fatih/structs

Он поддерживает:

  • Преобразование структуры в карту
  • Извлеките поля структуры в []string
  • Извлеките значения структуры в []values
  • Проверьте, была ли инициализирована структура или нет
  • Проверьте, является ли переданный интерфейс структурой или указателем на struct

Здесь вы можете увидеть несколько примеров: http://godoc.org/github.com/fatih/structs#pkg-examples Например, преобразование структуры в карту является простым:

type Server struct {
    Name    string
    ID      int32
    Enabled bool
}

s := &Server{
    Name:    "gopher",
    ID:      123456,
    Enabled: true,
}

// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(s)

Пакет structs поддерживает анонимные (встроенные) поля и вложенные структуры. Пакет обеспечивает фильтрацию определенных полей с помощью тегов полей.

Ответ 2

От struct к map[string]interface{}

package main

import (
    "fmt"
    "encoding/json"
)

type MyData struct {
    One   int
    Two   string
    Three int
}

func main() {   
    in := &MyData{One: 1, Two: "second"}

    var inInterface map[string]interface{}
    inrec, _ := json.Marshal(in)
    json.Unmarshal(inrec, &inInterface)

    // iterate through inrecs
    for field, val := range inInterface {
            fmt.Println("KV Pair: ", field, val)
    }
}

пойти на площадку здесь

Ответ 3

Вот функция, которую я написал в прошлом, чтобы преобразовать структуру в карту, используя теги в виде ключей

// ToMap converts a struct to a map using the struct tags.
//
// ToMap uses tags on struct fields to decide which fields to add to the
// returned map.
func ToMap(in interface{}, tag string) (map[string]interface{}, error){
    out := make(map[string]interface{})

    v := reflect.ValueOf(in)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }

    // we only accept structs
    if v.Kind() != reflect.Struct {
        return nil, fmt.Errorf("ToMap only accepts structs; got %T", v)
    }

    typ := v.Type()
    for i := 0; i < v.NumField(); i++ {
        // gets us a StructField
        fi := typ.Field(i)
        if tagv := fi.Tag.Get(tag); tagv != "" {
            // set key of map to value in struct field
            out[tagv] = v.Field(i).Interface()
        }
    }
    return out, nil
}

Runnable пример здесь.

Обратите внимание, что если у вас несколько полей с одинаковым значением тега, вы, очевидно, не сможете хранить их на карте. Возможно, разумно вернуть ошибку, если это произойдет.

Ответ 4

package main

import (
    "fmt"
    "reflect"
)

type bill struct {
    N1 int
    N2 string
    n3 string
}

func main() {
    a := bill{4, "dhfthf", "fdgdf"}

    v := reflect.ValueOf(a)

    values := make(map[string]interface{}, v.NumField())

    for i := 0; i < v.NumField(); i++ {
        if v.Field(i).CanInterface() {
            values[v.Type().Field(i).Name] = v.Field(i).Interface()
        } else {
            fmt.Printf("sorry you have a unexported field (lower case) value you are trying to sneak past. I will not allow it: %v\n", v.Type().Field(i).Name)
        }
    }

    fmt.Println(values)

    passObject(&values)
}

func passObject(v1 *map[string]interface{}) {
    fmt.Println("yoyo")
}

Ответ 5

Я не могу рекомендовать достаточно https://github.com/mitchellh/mapstructure, который преобразует структуры в карты и наоборот очень гладким способом.