func compareElem(diffs []Diff, fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) ([]Diff, error) {
	elemDiffs, err := compareRecursively(
		fieldPrefix,
		exp, act,
		expVisit, actVisit,
	)
	if err != nil {
		return diffs, err
	} else if len(elemDiffs) > 0 {
		diffs = append(diffs, elemDiffs...)
	}
	return diffs, err
}
util function for comparing and updating elements inside a slice, array, map or structure
it accepts an array of diff, and append elements if necessary
package compare
import (
	"reflect"
	"fmt"
)
type (
	Diff struct {
		Field    string       
		Expected interface{}  
		Actual   interface{}  
	}
	visitedPtrs map[uintptr]bool
)
func Compare(expected, actual interface{}) (diffs []Diff, err error) {
	exp := reflect.ValueOf(expected)
	act := reflect.ValueOf(actual)
	expVisit := visitedPtrs{}
	actVisit := visitedPtrs{}
	return compareRecursively("", exp, act, expVisit, actVisit)
}
func compareRecursively(fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) (diffs []Diff, err error) {
	if exp.Type() != act.Type() {
		return nil, fmt.Errorf("mismatched type of `%s`, exp.Type=%s, act.Type=%s", fieldPrefix, exp.Type(), act.Type())
	}
	if isPrimitiveType(exp.Kind()) {
		if !reflect.DeepEqual(exp.Interface(), act.Interface()) {
			diffs = newSingleDiffList(fieldPrefix, exp, act)
		}
		return  
	}
	if isStructType(exp.Kind()) {
		return compareStruct(fieldPrefix, exp, act, expVisit, actVisit)
	}
	if isArrayType(exp.Kind()) {
		return compareSliceOrArray(fieldPrefix, exp, act, expVisit, actVisit)
	}
	if exp.IsNil() && act.IsNil() {
		return
	} else if exp.IsNil() || act.IsNil() {
		return newSingleDiffList(fieldPrefix, exp, act), nil
	}
	if isPointerType(exp.Kind()) {
		return comparePointer(fieldPrefix, exp, act, expVisit, actVisit)
	}
	if isSliceType(exp.Kind()) {
		return compareSliceOrArray(fieldPrefix, exp, act, expVisit, actVisit)
	}
	if isMapType(exp.Kind()) {
		return compareMap(fieldPrefix, exp, act, expVisit, actVisit)
	}
	return nil, fmt.Errorf("invalid type found, field %s, exp.Type=%#v, act.Type=%#v", fieldPrefix, exp.Type(), act.Type())
}
func newSingleDiffList(field string, exp, act reflect.Value) []Diff {
	return []Diff{{
		Field:    field,
		Expected: exp.Interface(),
		Actual:   act.Interface(),
	}}
}
func comparePointer(fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) (diffs []Diff, err error) {
	if expVisit[exp.Pointer()] || actVisit[exp.Pointer()] {
		return  
	}
	return compareRecursively(fmt.Sprintf("*(%s)", fieldPrefix), reflect.Indirect(exp), reflect.Indirect(act), expVisit, actVisit)
}
func compareSliceOrArray(fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) (diffs []Diff, err error) {
	if exp.Len() != act.Len() {
		return nil, fmt.Errorf("mismatched len of `%s`, exp.Len=%d, act.Len=%d", fieldPrefix, exp.Len(), act.Len())
	}
	if exp.Len() == 0 {
		return
	}
	for i, l := 0, exp.Len(); i < l; i++ {
		if diffs, err = compareElem(
			diffs,
			fmt.Sprintf("%s[%d]", fieldPrefix, i),
			exp.Index(i), act.Index(i),
			expVisit, actVisit,
		); err != nil {
			return
		}
	}
	return
}
func compareMap(fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) (diffs []Diff, err error) {
	if exp.Len() != act.Len() {
		return nil, fmt.Errorf("mismatched len of `%s`, exp.Len=%d, act.Len=%d", fieldPrefix, exp.Len(), act.Len())
	}
	if exp.Len() == 0 {
		return
	}
	for _, key := range exp.MapKeys() {
		if diffs, err = compareElem(
			diffs,
			fmt.Sprintf("%s[%v]", fieldPrefix, key.String()),
			exp.MapIndex(key), act.MapIndex(key),
			expVisit, actVisit,
		); err != nil {
			return
		}
	}
	return
}
func compareStruct(fieldPrefix string, exp, act reflect.Value, expVisit, actVisit visitedPtrs) (diffs []Diff, err error) {
	typ := exp.Type()
	var fieldName string
	var expField, actField reflect.Value
	var subFieldPrefix string
	for i, l := 0, typ.NumField(); i < l; i++ {
		fieldName = typ.Field(i).Name
		subFieldPrefix = fmt.Sprintf("%s.%s", fieldPrefix, fieldName)
		expField = exp.FieldByName(fieldName)
		actField = act.FieldByName(fieldName)
		if actField == (reflect.Value{}) {
			return nil, fmt.Errorf("field=`%s` not found in act", subFieldPrefix)
		}
		if diffs, err = compareElem(diffs, subFieldPrefix, expField, actField, expVisit, actVisit); err != nil {
			return
		}
	}
	return
}