func typesMatch(a, b interface{}) bool {
	return strings.TrimPrefix(reflect.TypeOf(a).String(), "*") == strings.TrimPrefix(reflect.TypeOf(b).String(), "*")
}
typesMatch typechecks two interfaces
package merger
import (
	"errors"
	"reflect"
	"strings"
)
var (
	ErrDistinctType = errors.New(`dst and src must be of the same type`)
	ErrNoPtr = errors.New(`dst must be a pointer to a struct`)
	ErrNilArguments = errors.New(`no nil values allowed`)
	ErrUnknown = errors.New(`could not merge`)
)
func Merge(dst, src interface{}) error {
	if dst == nil || src == nil {
		return ErrNilArguments
	}
	if !isStructPtr(dst) {
		return ErrNoPtr
	}
	if !typesMatch(src, dst) {
		return ErrDistinctType
	}
	vSrc := getValue(src)
	vDst := getValue(dst)
	for i := 0; i < vSrc.NumField(); i++ {
		df := vDst.Field(i)
		sf := vSrc.Field(i)
		if err := merge(df, sf); err != nil {
			return err
		}
	}
	return nil
}
func merge(dst, src reflect.Value) (err error) {
	if dst.CanSet() && !isZero(src) {
		switch dst.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
			reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
			if isZero(dst) {
				switch dst.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
					dst.SetInt(src.Int())
				case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
					dst.SetUint(src.Uint())
				case reflect.Float32, reflect.Float64:
					dst.SetFloat(src.Float())
				case reflect.String:
					dst.SetString(src.String())
				case reflect.Bool:
					dst.SetBool(src.Bool())
				}
			}
		case reflect.Slice:
			dst.Set(mergeSlice(dst, src))
		case reflect.Struct:
			if fnZero, ok := dst.Type().MethodByName(`IsZero`); ok {
				res := fnZero.Func.Call([]reflect.Value{dst})
				if len(res) > 0 {
					if v, isok := res[0].Interface().(bool); isok && v {
						dst.Set(src)
					}
				}
			}
			for i := 0; i < src.NumField(); i++ {
				df := dst.Field(i)
				sf := src.Field(i)
				if err := merge(df, sf); err != nil {
					return err
				}
			}
		case reflect.Map:
			dst.Set(mergeMap(dst, src))
		case reflect.Ptr:
			if !dst.IsNil() {
				dst = getValue(dst)
			} else {
				dst.Set(src)
				break
			}
			if src.CanAddr() && src.IsNil() {
				src = getValue(src)
				if err := merge(dst, src); err != nil {
					return err
				}
			}
		default:
			return ErrUnknown
		}
	}
	return
}
func mergeSlice(dst, src reflect.Value) (res reflect.Value) {
	for i := 0; i < src.Len(); i++ {
		if i >= dst.Len() {
			dst = reflect.Append(dst, src.Index(i))
		}
		if err := merge(dst.Index(i), src.Index(i)); err != nil {
			res = dst
			return
		}
	}
	res = dst
	return
}
func mergeMap(dst, src reflect.Value) (res reflect.Value) {
	if dst.IsNil() {
		dst = reflect.MakeMap(dst.Type())
	}
	for _, k := range src.MapKeys() {
		vs := src.MapIndex(k)
		vd := dst.MapIndex(k)
		if !vd.IsValid() && isZero(vd) && !isZero(vs) {
			dst.SetMapIndex(k, vs)
		}
	}
	return dst
}