Introduction to the mergo Library

This article briefly introduces the mergo library and some commonly used parameters. mergo also provides more complex parameters.

mergo is designed to conveniently merge structs and maps, allowing the assignment of struct field values to maps and map values to struct fields. mergo merges structs and maps of the same type by setting default values in zero-value fields. It does not merge unexported (private) fields and recursively merges any exported fields. It also does not merge structs within maps (as they cannot be addressed using Go reflection). mergo is used in many well-known projects, such as containerd, k8s, loki, etc.

To install mergo, use the following command:

go get -u github.com/imdario/mergo

Basic Usage

mergo provides two main functions: Merge and Map. Merge is used to combine two structs of the same type, while Map is for assigning values between structs and maps.

Example:

package main

import (
    "fmt"
    "log"
    "github.com/imdario/mergo"
)

type redisConfig struct {
    Address   string
    Port      int
    DB        int
    UserName  string
    PassWord  string
}

var defaultConfig = redisConfig{
    Address: "127.0.0.1",
    Port:     6379,
    DB:       1,
    UserName: "123",
    PassWord: "123",
}

func main() {
    var config redisConfig
    if err := mergo.Merge(&config, defaultConfig); err != nil {
        log.Fatal(err)
    }
    fmt.Println("redis address:", config.Address)
    fmt.Println("redis port:", config.Port)
    fmt.Println("redis db:", config.DB)
    fmt.Println("redis username:", config.UserName)
    fmt.Println("redis password:", config.PassWord)

    var m = make(map[string]interface{})
    if err := mergo.Map(&m, defaultConfig); err != nil {
        log.Fatal(err)
    }
    fmt.Println(m)
}

Advanced Usage

Overriding

If the target struct already has initial values, the Merge/Map functions will not override existing values. To override the original values, you need to use the WithOverride parameter.

var config redisConfig
config.UserName = "overstarry"
if err := mergo.Merge(&config, defaultConfig, mergo.WithOverride); err != nil {
    log.Fatal(err)
}

If you need to check whether the types of the objects being merged are consistent, you can use the mergo.WithTypeCheck parameter. To override pointers, you need to use the WithoutDereference parameter.

Slices

If a struct field is of slice type and you want to merge two slices during the override, use the WithAppendSlice parameter.

if err := mergo.Merge(&config, defaultConfig, mergo.WithAppendSlice); err != nil {
    log.Fatal(err)
}

References