gostructgo-map

In Go is there a way to convert map of structure to slice of structure


I have to convert map of structure to slice of structure in Golang, i.e. source to target structure specified below.

// Source
var source map[string]Category

type Category struct {
    A           int
    SubCategory map[string]SubCategory
}

type SubCategory struct {
    B int
    C string
}

// Target
var target []OldCategory

type OldCategory struct {
    OldA           int `mapstructure:"A"`
    OldSubCategory []OldSubCategory
}

type OldSubCategory struct {
    OldB int    `mapstructure:"B"`
    OldC string `mapstructure:"C"`
}

I am referring mapstrucuture package ("github.com/mitchellh/mapstructure"). One way to convert from source to target is to iterate on all the SubCategory and then Category in source instance and use mapstructure.Decode() to convert each one individually.

Is there a direct way using mapstrucuture package, wherein I create a custom decoder hook using NewDecoder and DecoderConfig.DecodeHook, and whenever I encounter source as a map of structure and target as a slice of structure, I handle it in the DecodeHookFunc function.

Relevant documentation of mapstructure https://godoc.org/github.com/mitchellh/mapstructure#NewDecoder


Solution

  • you could do it using mapstructure decoder hooks, write custom logic inside the decoder hook , to do your job. But there is no standard lib function to do your job.

    Example:

    dc := &mapstructure.DecoderConfig{Result: target, DecodeHook: customHook}
        ms, err := mapstructure.NewDecoder(dc)
        if err != nil {
            return err
        }
    
        err = ms.Decode(source)
        if err != nil {
            return err
        }
    
    func customHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
    if f.Kind() == reflect.Int && t.Kind() == reflect.Bool {
        var result bool
        if data == 1 {
            result = true
        }
        return result, nil
    
    }
    

    So you could technically decode anything to anything using custom hooks as long it has your custom logic.