2020-06-18 02:29:38 +03:00
// Copyright 2013 Dario Castañé. All rights reserved.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/ *
2020-10-16 08:06:27 +03:00
A helper to merge structs and maps in Golang . Useful for configuration default values , avoiding messy if - statements .
2020-06-18 02:29:38 +03:00
2020-10-16 08:06:27 +03:00
Mergo merges same - type structs and maps by setting default values in zero - value fields . Mergo won ' t merge unexported ( private ) fields . It will do recursively any exported one . It also won ' t merge structs inside maps ( because they are not addressable using Go reflection ) .
Status
It is ready for production use . It is used in several projects by Docker , Google , The Linux Foundation , VMWare , Shopify , etc .
Important note
Please keep in mind that a problematic PR broke 0.3 .9 . We reverted it in 0.3 .10 . We consider 0.3 .10 as stable but not bug - free . . Also , this version adds suppot for go modules .
Keep in mind that in 0.3 .2 , Mergo changed Merge ( ) and Map ( ) signatures to support transformers . We added an optional / variadic argument so that it won ' t break the existing code .
If you were using Mergo before April 6 th , 2015 , please check your project works as intended after updating your local copy with go get - u github . com / imdario / mergo . I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change ( release 0.2 .0 ) .
Install
Do your usual installation procedure :
go get github . com / imdario / mergo
// use in your .go code
import (
"github.com/imdario/mergo"
)
2020-06-18 02:29:38 +03:00
Usage
2020-10-16 08:06:27 +03:00
You can only merge same - type structs with exported fields initialized as zero value of their type and same - types maps . Mergo won ' t merge unexported ( private ) fields but will do recursively any exported one . It won ' t merge empty structs value as they are zero values too . Also , maps will be merged recursively except for structs inside maps ( because they are not addressable using Go reflection ) .
if err := mergo . Merge ( & dst , src ) ; err != nil {
// ...
}
Also , you can merge overwriting values using the transformer WithOverride .
if err := mergo . Merge ( & dst , src , mergo . WithOverride ) ; err != nil {
// ...
}
Additionally , you can map a map [ string ] interface { } to a struct ( and otherwise , from struct to map ) , following the same restrictions as in Merge ( ) . Keys are capitalized to find each corresponding exported field .
if err := mergo . Map ( & dst , srcMap ) ; err != nil {
// ...
}
Warning : if you map a struct to map , it won ' t do it recursively . Don ' t expect Mergo to map struct members of your struct as map [ string ] interface { } . They will be just assigned as values .
Here is a nice example :
package main
import (
"fmt"
"github.com/imdario/mergo"
)
2020-06-18 02:29:38 +03:00
2020-10-16 08:06:27 +03:00
type Foo struct {
A string
B int64
2020-06-18 02:29:38 +03:00
}
2020-10-16 08:06:27 +03:00
func main ( ) {
src := Foo {
A : "one" ,
B : 2 ,
}
dest := Foo {
A : "two" ,
}
mergo . Merge ( & dest , src )
fmt . Println ( dest )
// Will print
// {two 2}
2020-06-18 02:29:38 +03:00
}
2020-10-16 08:06:27 +03:00
Transformers
Transformers allow to merge specific types differently than in the default behavior . In other words , now you can customize how some types are merged . For example , time . Time is a struct ; it doesn ' t have zero value but IsZero can return true because it has fields with zero value . How can we merge a non - zero time . Time ?
package main
import (
"fmt"
"github.com/imdario/mergo"
"reflect"
"time"
)
type timeTransformer struct {
2020-06-18 02:29:38 +03:00
}
2020-10-16 08:06:27 +03:00
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
// ...
}
2020-06-18 02:29:38 +03:00
2020-10-16 08:06:27 +03:00
func main ( ) {
src := Snapshot { time . Now ( ) }
dest := Snapshot { }
mergo . Merge ( & dest , src , mergo . WithTransformers ( timeTransformer { } ) )
fmt . Println ( dest )
// Will print
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
2020-06-18 02:29:38 +03:00
}
2020-10-16 08:06:27 +03:00
Contact me
If I can help you , you have an idea or you are using Mergo in your projects , don ' t hesitate to drop me a line ( or a pull request ) : https : //twitter.com/im_dario
About
Written by Dario Castañé : https : //da.rio.hn
License
BSD 3 - Clause license , as Go language .
2020-06-18 02:29:38 +03:00
* /
package mergo