Skip to content

Instantly share code, notes, and snippets.

@gebv
Last active July 5, 2016 15:43
Show Gist options
  • Select an option

  • Save gebv/f2aebb34806bf40d48ba8c03b9653e6d to your computer and use it in GitHub Desktop.

Select an option

Save gebv/f2aebb34806bf40d48ba8c03b9653e6d to your computer and use it in GitHub Desktop.
append or replace struct, slice, map golang
package utils
import (
"errors"
"reflect"
)
func resolveValues(dst, src interface{}) (vdst reflect.Value, vsrc reflect.Value, err error) {
if dst == nil || src == nil {
err = errors.New("nil args")
return
}
// destination
vdst = reflect.ValueOf(dst)
if vdst.Kind() == reflect.Ptr {
vdst = vdst.Elem()
}
if vdst.Kind() != reflect.Struct &&
vdst.Kind() != reflect.Slice &&
vdst.Kind() != reflect.Map {
err = errors.New("not supported")
return
}
// source
vsrc = reflect.ValueOf(src)
if vsrc.Kind() == reflect.Ptr {
vsrc = vsrc.Elem()
}
if vdst.Type() != vsrc.Type() {
err = errors.New("diff args types")
return
}
return
}
func appendOrReplace(vdst, vsrc reflect.Value) error {
switch vdst.Kind() {
case reflect.Struct:
for i := 0; i < vdst.NumField(); i++ {
if err := appendOrReplace(vdst.Field(i), vsrc.Field(i)); err != nil {
return err
}
}
case reflect.Map:
for _, key := range vsrc.MapKeys() {
vdst.SetMapIndex(key, vsrc.MapIndex(key))
}
case reflect.Slice:
for i := 0; i < vsrc.Len(); i++ {
vdst.Set(reflect.Append(vdst, vsrc.Index(i)))
}
default:
if vdst.CanSet() {
vdst.Set(vsrc)
}
}
return nil
}
func AppendOrReplace(d, s interface{}) error {
vd, vs, err := resolveValues(d, s)
if err != nil {
return err
}
return appendOrReplace(vd, vs)
}
package utils
import (
"reflect"
"testing"
)
type simpleSubType struct {
A string
}
type simpleType struct {
A []string
B string
C []simpleSubType
D map[string]string
E map[string]simpleSubType
G *simpleSubType
F map[string]*simpleSubType
}
func TestAppendOrReplace(t *testing.T) {
s := simpleType{[]string{"a", "b"},
"a",
[]simpleSubType{simpleSubType{"a"}, simpleSubType{"b"}},
map[string]string{"a": "b", "c": "d"},
map[string]simpleSubType{
"a": simpleSubType{"b"},
"c": simpleSubType{"d"},
},
&simpleSubType{"a"},
map[string]*simpleSubType{
"a": &simpleSubType{"b"},
"c": &simpleSubType{"d"},
},
}
d := simpleType{[]string{"b", "c"},
"b",
[]simpleSubType{simpleSubType{"c"}, simpleSubType{"d"}},
map[string]string{"a": "z", "c": "y", "e": "f"},
map[string]simpleSubType{
"a": simpleSubType{"z"},
"c": simpleSubType{"y"},
"e": simpleSubType{"f"},
},
&simpleSubType{"b"},
map[string]*simpleSubType{
"a": &simpleSubType{"z"},
"c": &simpleSubType{"y"},
"e": &simpleSubType{"f"},
},
}
// expected
e := simpleType{
[]string{"b", "c", "a", "b"},
"a",
[]simpleSubType{simpleSubType{"c"}, simpleSubType{"d"}, simpleSubType{"a"}, simpleSubType{"b"}},
map[string]string{"a": "b", "c": "d", "e": "f"},
map[string]simpleSubType{
"a": simpleSubType{"b"},
"c": simpleSubType{"d"},
"e": simpleSubType{"f"},
},
&simpleSubType{"a"},
map[string]*simpleSubType{
"a": &simpleSubType{"b"},
"c": &simpleSubType{"d"},
"e": &simpleSubType{"f"},
},
}
AppendOrReplace(&d, s)
if !reflect.DeepEqual(d, e) {
t.FailNow()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment