Install Mergo
masterTo use Mergo in your Go project, install it using go get and import it using the vanity URL dario.cat/mergo.
go get dario.cat/mergorepository·master·Indexed 25 days ago
https://github.com/darccio/mergoA Go helper library for merging structs and maps, specifically designed for applying default values to configuration structs by filling in zero-value fields. It supports recursive merging of exported fields, custom merge behavior via Transformers, and functional options such as WithOverride, WithAppendSlice, and WithoutDereference. It also provides functionality to map map[string]interface{} to structs and vice versa using mergo.Map().
To use Mergo in your Go project, install it using go get and import it using the vanity URL dario.cat/mergo.
go get dario.cat/mergoAs of version 1.0.0, Mergo uses the vanity URL dario.cat/mergo. If your project or its dependencies are having issues with this change, you can use a Go replace directive to pin the version to the last one using the old import URL:
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16Transformers allow you to define custom logic for how specific types are merged. You must implement the Transformer interface, which returns a function that handles the reflect.Value of the destination and source.
package main
import (
"fmt"
"dario.cat/mergo"
"reflect"
"time"
)
type timeTransformer struct {
}
func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
if typ == reflect.TypeOf(time.Time{}) {
return func(dst, src reflect.Value) error {
if dst.CanSet() {
isZero := dst.MethodByName("IsZero")
result := isZero.Call([]reflect.Value{})
if result[0].Bool() {
dst.Set(src)
}
}
return nil
}
}
return nil
}
type Snapshot struct {
Time time.Time
// ...
}
func main() {
src := Snapshot{time.Now()}
dest := Snapshot{}
mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
fmt.Println(dest)
}Use mergo.Merge(&dst, src) to merge src into dst.
Constraints:
If dst has a non-zero value in a field, src will only overwrite it if you use the mergo.WithOverride transformer.
if err := mergo.Merge(&dst, src); err != nil {
// ...
}If you need to override pointers such that the source pointer's value is assigned to the destination's pointer (rather than merging the values the pointers point to), use the mergo.WithoutDereference transformer.
package main
import (
"fmt"
"dario.cat/mergo"
)
type Foo struct {
A *string
B int64
}
func main() {
first := "first"
second := "second"
src := Foo{
A: &first,
B: 2,
}
dest := Foo{
A: &second,
B: 1,
}
mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
}By default, Mergo only sets values in dst if they are currently the zero value. To force src values to overwrite existing non-zero values in dst, use the mergo.WithOverride transformer.
if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
// ...
}You can map a map[string]interface{} to a struct (or vice versa) using mergo.Map(&dst, srcMap).
Notes:
map[string]interface{}.if err := mergo.Map(&dst, srcMap); err != nil {
// ...
}The Config struct defines the internal settings for the merge operation. While typically configured via functional options, you can interact with these fields directly if building custom extensions:
| Field | Description |
|---|---|
Transformers | Custom type-specific merging logic |
Overwrite | If true, non-empty dst values are replaced by src values |
ShouldNotDereference | If true, pointers are not dereferenced when checking for empty values |
AppendSlice | If true, slices are appended instead of replaced |
TypeCheck | If true, validates that types match during an overwrite |
overwriteWithEmptyValue | (Internal) Overwrites dst even if src is empty |
overwriteSliceWithEmptyValue | (Internal) Overwrites slices even if src is empty |
sliceDeepCopy | (Internal) Performs a deep merge on slice elements |
mergo uses functional options to configure the Config object passed to the merge process. Common options include:
WithOverride(): Overrides non-empty dst attributes with non-empty src values.WithOverwriteWithEmptyValue(): Overrides non-empty dst attributes even with empty src values.WithAppendSlice(): Appends src slices to dst slices instead of overwriting them.WithTypeCheck(): Ensures types match when overwriting (must be used with WithOverride).WithSliceDeepCopy(): Merges slice elements one-by-one using the Overwrite logic.WithoutDereference(): Prevents dereferencing pointers when checking if they are empty (a non-nil pointer is never considered empty).WithTransformers(transformers): Allows custom merging logic for specific types via the Transformers interface.Mergo returns the following errors when encountering invalid arguments or unsupported types during a merge operation:
var (
ErrNilArguments = errors.New("src and dst must not be nil")
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
ErrNotSupported = errors.New("only structs, maps, and slices are supported")
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
ErrNonPointerArgument = errors.New("dst must be a pointer")
)The Transformers interface allows you to define custom merging logic for specific types. You implement the Transformer method, which returns a function that takes the destination and source reflect.Value and returns an error.
type Transformers interface {
Transformer(reflect.Type) func(dst, src reflect.Value) error
}