function for converting a struct to map in Golang

前端 未结 5 1262
囚心锁ツ
囚心锁ツ 2020-12-07 18:38

I want to convert a struct to map in Golang. It would also be nice if I could use the JSON tags as keys in the created map (otherwise defaulting to field name).

Edi

相关标签:
5条回答
  • 2020-12-07 18:53
    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")
    }
    
    0 讨论(0)
  • 2020-12-07 18:54

    From struct to 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)
        }
    }
    

    go playground here

    0 讨论(0)
  • 2020-12-07 19:03

    I like the importable package for the accepted answer, but it does not translate my json aliases. Most of my projects have a helper function/class that I import.

    Here is a function that solves my specific problem.

    
    // Converts a struct to a map while maintaining the json alias as keys
    func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
        data, err := json.Marshal(obj) // Convert to a json string
    
        if err != nil {
            return
        }
    
        err = json.Unmarshal(data, &newMap) // Convert to a map
        return
    }
    
    

    And in the main, this is how it would be called...

    package main
    
    import (
        "fmt"
        "encoding/json"
        "github.com/fatih/structs"
    )
    
    type MyStructObject struct {
        Email string `json:"email_address"`
    }
    
    func main() {
        obj := &MyStructObject{Email: "test@test.com"}
    
        // My solution
        fmt.Println(StructToMap(obj)) // prints {"email_address": "test@test.com"}
    
        // The currently accepted solution
        fmt.Println(structs.Map(obj)) // prints {"Email": "test@test.com"}
    }
    
    0 讨论(0)
  • 2020-12-07 19:13

    I also had need for something like this. I was using an internal package which was converting a struct to a map. I decided to open source it with other struct based high level functions. Have a look:

    https://github.com/fatih/structs

    It has support for:

    • Convert struct to a map
    • Extract the fields of a struct to a []string
    • Extract the values of a struct to a []values
    • Check if a struct is initialized or not
    • Check if a passed interface is a struct or a pointer to struct

    You can see some examples here: http://godoc.org/github.com/fatih/structs#pkg-examples For example converting a struct to a map is a simple:

    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)
    

    The structs package has support for anonymous (embedded) fields and nested structs. The package provides to filter certain fields via field tags.

    0 讨论(0)
  • 2020-12-07 19:14

    Here is a function I've written in the past to convert a struct to a map, using tags as keys

    // ToMap converts a struct to a map using the struct's 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 example here.

    Note, if you have multiple fields with the same tag value, then you will obviously not be able to store them all within a map. It might be prudent to return an error if that happens.

    0 讨论(0)
提交回复
热议问题