func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
	overwrite := config.Overwrite
	typeCheck := config.TypeCheck
	overwriteWithEmptySrc := config.overwriteWithEmptyValue
	config.overwriteWithEmptyValue = false

	if !src.IsValid() {
		return
	}
	if dst.CanAddr() {
		addr := dst.UnsafeAddr()
		h := 17 * addr
		seen := visited[h]
		typ := dst.Type()
		for p := seen; p != nil; p = p.next {
			if p.ptr == addr && p.typ == typ {
				return nil
			}
		}
		// Remember, remember...
		visited[h] = &visit{addr, typ, seen}
	}

	if config.Transformers != nil && !isEmptyValue(dst) {
		if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
			err = fn(dst, src)
			return
		}
	}

	switch dst.Kind() {
	case reflect.Struct:
		if hasExportedField(dst) {
			for i, n := 0, dst.NumField(); i < n; i++ {
				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
					return
				}
			}
		} else {
			if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
				dst.Set(src)
			}
		}
	case reflect.Map:
		if dst.IsNil() && !src.IsNil() {
			dst.Set(reflect.MakeMap(dst.Type()))
		}
		for _, key := range src.MapKeys() {
			srcElement := src.MapIndex(key)
			if !srcElement.IsValid() {
				continue
			}
			dstElement := dst.MapIndex(key)
			switch srcElement.Kind() {
			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
				if srcElement.IsNil() {
					continue
				}
				fallthrough
			default:
				if !srcElement.CanInterface() {
					continue
				}
				switch reflect.TypeOf(srcElement.Interface()).Kind() {
				case reflect.Struct:
					fallthrough
				case reflect.Ptr:
					fallthrough
				case reflect.Map:
					srcMapElm := srcElement
					dstMapElm := dstElement
					if srcMapElm.CanInterface() {
						srcMapElm = reflect.ValueOf(srcMapElm.Interface())
						if dstMapElm.IsValid() {
							dstMapElm = reflect.ValueOf(dstMapElm.Interface())
						}
					}
					if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
						return
					}
				case reflect.Slice:
					srcSlice := reflect.ValueOf(srcElement.Interface())

					var dstSlice reflect.Value
					if !dstElement.IsValid() || dstElement.IsNil() {
						dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
					} else {
						dstSlice = reflect.ValueOf(dstElement.Interface())
					}

					if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
						if typeCheck && srcSlice.Type() != dstSlice.Type() {
							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
						}
						dstSlice = srcSlice
					} else if config.AppendSlice {
						if srcSlice.Type() != dstSlice.Type() {
							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
						}
						dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
					}
					dst.SetMapIndex(key, dstSlice)
				}
			}
			if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
				continue
			}

			if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
				if dst.IsNil() {
					dst.Set(reflect.MakeMap(dst.Type()))
				}
				dst.SetMapIndex(key, srcElement)
			}
		}
	case reflect.Slice:
		if !dst.CanSet() {
			break
		}
		if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
			dst.Set(src)
		} else if config.AppendSlice {
			if src.Type() != dst.Type() {
				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
			}
			dst.Set(reflect.AppendSlice(dst, src))
		}
	case reflect.Ptr:
		fallthrough
	case reflect.Interface:
		if src.IsNil() {
			break
		}

		if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
			if dst.IsNil() || overwrite {
				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
					dst.Set(src)
				}
			}
			break
		}

		if src.Kind() != reflect.Interface {
			if dst.IsNil() || overwrite {
				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
					dst.Set(src)
				}
			} else if src.Kind() == reflect.Ptr {
				if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
					return
				}
			} else if dst.Elem().Type() == src.Type() {
				if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
					return
				}
			} else {
				return ErrDifferentArgumentsTypes
			}
			break
		}
		if dst.IsNil() || overwrite {
			if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
				dst.Set(src)
			}
		} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
			return
		}
	default:
		if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
			dst.Set(src)
		}
	}
	return
}
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
	overwrite := config.Overwrite
	typeCheck := config.TypeCheck
	overwriteWithEmptySrc := config.overwriteWithEmptyValue
	config.overwriteWithEmptyValue = false

	if !src.IsValid() {
		return
	}
	if dst.CanAddr() {
		addr := dst.UnsafeAddr()
		h := 17 * addr
		seen := visited[h]
		typ := dst.Type()
		for p := seen; p != nil; p = p.next {
			if p.ptr == addr && p.typ == typ {
				return nil
			}
		}
		
		visited[h] = &visit{addr, typ, seen}
	}

	if config.Transformers != nil && !isEmptyValue(dst) {
		if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
			err = fn(dst, src)
			return
		}
	}

	switch dst.Kind() {
	case reflect.Struct:
		if hasExportedField(dst) {
			for i, n := 0, dst.NumField(); i < n; i++ {
				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
					return
				}
			}
		} else {
			if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
				dst.Set(src)
			}
		}
	case reflect.Map:
		if dst.IsNil() && !src.IsNil() {
			dst.Set(reflect.MakeMap(dst.Type()))
		}
		for _, key := range src.MapKeys() {
			srcElement := src.MapIndex(key)
			if !srcElement.IsValid() {
				continue
			}
			dstElement := dst.MapIndex(key)
			switch srcElement.Kind() {
			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
				if srcElement.IsNil() {
					continue
				}
				fallthrough
			default:
				if !srcElement.CanInterface() {
					continue
				}
				switch reflect.TypeOf(srcElement.Interface()).Kind() {
				case reflect.Struct:
					fallthrough
				case reflect.Ptr:
					fallthrough
				case reflect.Map:
					srcMapElm := srcElement
					dstMapElm := dstElement
					if srcMapElm.CanInterface() {
						srcMapElm = reflect.ValueOf(srcMapElm.Interface())
						if dstMapElm.IsValid() {
							dstMapElm = reflect.ValueOf(dstMapElm.Interface())
						}
					}
					if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
						return
					}
				case reflect.Slice:
					srcSlice := reflect.ValueOf(srcElement.Interface())

					var dstSlice reflect.Value
					if !dstElement.IsValid() || dstElement.IsNil() {
						dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
					} else {
						dstSlice = reflect.ValueOf(dstElement.Interface())
					}

					if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
						if typeCheck && srcSlice.Type() != dstSlice.Type() {
							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
						}
						dstSlice = srcSlice
					} else if config.AppendSlice {
						if srcSlice.Type() != dstSlice.Type() {
							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
						}
						dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
					}
					dst.SetMapIndex(key, dstSlice)
				}
			}
			if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
				continue
			}

			if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
				if dst.IsNil() {
					dst.Set(reflect.MakeMap(dst.Type()))
				}
				dst.SetMapIndex(key, srcElement)
			}
		}
	case reflect.Slice:
		if !dst.CanSet() {
			break
		}
		if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
			dst.Set(src)
		} else if config.AppendSlice {
			if src.Type() != dst.Type() {
				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
			}
			dst.Set(reflect.AppendSlice(dst, src))
		}
	case reflect.Ptr:
		fallthrough
	case reflect.Interface:
		if src.IsNil() {
			break
		}

		if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
			if dst.IsNil() || overwrite {
				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
					dst.Set(src)
				}
			}
			break
		}

		if src.Kind() != reflect.Interface {
			if dst.IsNil() || overwrite {
				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
					dst.Set(src)
				}
			} else if src.Kind() == reflect.Ptr {
				if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
					return
				}
			} else if dst.Elem().Type() == src.Type() {
				if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
					return
				}
			} else {
				return ErrDifferentArgumentsTypes
			}
			break
		}
		if dst.IsNil() || overwrite {
			if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
				dst.Set(src)
			}
		} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
			return
		}
	default:
		if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
			dst.Set(src)
		}
	}
	return
}
func deepMerge ( dst , src reflect . Value , visited map [ uintptr ] * visit , depth int , config * Config ) ( err error ) { overwrite := config . Overwrite typeCheck := config . TypeCheck overwriteWithEmptySrc := config . overwriteWithEmptyValue config . overwriteWithEmptyValue = false if ! src . IsValid ( ) { return } if dst . CanAddr ( ) { addr := dst . UnsafeAddr ( ) h := 17 * addr seen := visited [ h ] typ := dst . Type ( ) for p := seen ; p != nil ; p = p . next { if p . ptr == addr && p . typ == typ { return nil } } // Remember, remember... visited [ h ] = & visit { addr , typ , seen } } if config . Transformers != nil && ! isEmptyValue ( dst ) { if fn := config . Transformers . Transformer ( dst . Type ( ) ) ; fn != nil { err = fn ( dst , src ) return } } switch dst . Kind ( ) { case reflect . Struct : if hasExportedField ( dst ) { for i , n := 0 , dst . NumField ( ) ; i < n ; i ++ { if err = deepMerge ( dst . Field ( i ) , src . Field ( i ) , visited , depth + 1 , config ) ; err != nil { return } } } else { if dst . CanSet ( ) && ( ! isEmptyValue ( src ) || overwriteWithEmptySrc ) && ( overwrite || isEmptyValue ( dst ) ) { dst . Set ( src ) } } case reflect . Map : if dst . IsNil ( ) && ! src . IsNil ( ) { dst . Set ( reflect . MakeMap ( dst . Type ( ) ) ) } for _ , key := range src . MapKeys ( ) { srcElement := src . MapIndex ( key ) if ! srcElement . IsValid ( ) { continue } dstElement := dst . MapIndex ( key ) switch srcElement . Kind ( ) { case reflect . Chan , reflect . Func , reflect . Map , reflect . Interface , reflect . Slice : if srcElement . IsNil ( ) { continue } fallthrough default : if ! srcElement . CanInterface ( ) { continue } switch reflect . TypeOf ( srcElement . Interface ( ) ) . Kind ( ) { case reflect . Struct : fallthrough case reflect . Ptr : fallthrough case reflect . Map : srcMapElm := srcElement dstMapElm := dstElement if srcMapElm . CanInterface ( ) { srcMapElm = reflect . ValueOf ( srcMapElm . Interface ( ) ) if dstMapElm . IsValid ( ) { dstMapElm = reflect . ValueOf ( dstMapElm . Interface ( ) ) } } if err = deepMerge ( dstMapElm , srcMapElm , visited , depth + 1 , config ) ; err != nil { return } case reflect . Slice : srcSlice := reflect . ValueOf ( srcElement . Interface ( ) ) var dstSlice reflect . Value if ! dstElement . IsValid ( ) || dstElement . IsNil ( ) { dstSlice = reflect . MakeSlice ( srcSlice . Type ( ) , 0 , srcSlice . Len ( ) ) } else { dstSlice = reflect . ValueOf ( dstElement . Interface ( ) ) } if ( ! isEmptyValue ( src ) || overwriteWithEmptySrc ) && ( overwrite || isEmptyValue ( dst ) ) && ! config . AppendSlice { if typeCheck && srcSlice . Type ( ) != dstSlice . Type ( ) { return fmt . Errorf ( " " , srcSlice . Type ( ) , dstSlice . Type ( ) ) } dstSlice = srcSlice } else if config . AppendSlice { if srcSlice . Type ( ) != dstSlice . Type ( ) { return fmt . Errorf ( " " , srcSlice . Type ( ) , dstSlice . Type ( ) ) } dstSlice = reflect . AppendSlice ( dstSlice , srcSlice ) } dst . SetMapIndex ( key , dstSlice ) } } if dstElement . IsValid ( ) && ! isEmptyValue ( dstElement ) && ( reflect . TypeOf ( srcElement . Interface ( ) ) . Kind ( ) == reflect . Map || reflect . TypeOf ( srcElement . Interface ( ) ) . Kind ( ) == reflect . Slice ) { continue } if srcElement . IsValid ( ) && ( overwrite || ( ! dstElement . IsValid ( ) || isEmptyValue ( dstElement ) ) ) { if dst . IsNil ( ) { dst . Set ( reflect . MakeMap ( dst . Type ( ) ) ) } dst . SetMapIndex ( key , srcElement ) } } case reflect . Slice : if ! dst . CanSet ( ) { break } if ( ! isEmptyValue ( src ) || overwriteWithEmptySrc ) && ( overwrite || isEmptyValue ( dst ) ) && ! config . AppendSlice { dst . Set ( src ) } else if config . AppendSlice { if src . Type ( ) != dst . Type ( ) { return fmt . Errorf ( " " , src . Type ( ) , dst . Type ( ) ) } dst . Set ( reflect . AppendSlice ( dst , src ) ) } case reflect . Ptr : fallthrough case reflect . Interface : if src . IsNil ( ) { break } if dst . Kind ( ) != reflect . Ptr && src . Type ( ) . AssignableTo ( dst . Type ( ) ) { if dst . IsNil ( ) || overwrite { if dst . CanSet ( ) && ( overwrite || isEmptyValue ( dst ) ) { dst . Set ( src ) } } break } if src . Kind ( ) != reflect . Interface { if dst . IsNil ( ) || overwrite { if dst . CanSet ( ) && ( overwrite || isEmptyValue ( dst ) ) { dst . Set ( src ) } } else if src . Kind ( ) == reflect . Ptr { if err = deepMerge ( dst . Elem ( ) , src . Elem ( ) , visited , depth + 1 , config ) ; err != nil { return } } else if dst . Elem ( ) . Type ( ) == src . Type ( ) { if err = deepMerge ( dst . Elem ( ) , src , visited , depth + 1 , config ) ; err != nil { return } } else { return ErrDifferentArgumentsTypes } break } if dst . IsNil ( ) || overwrite { if dst . CanSet ( ) && ( overwrite || isEmptyValue ( dst ) ) { dst . Set ( src ) } } else if err = deepMerge ( dst . Elem ( ) , src . Elem ( ) , visited , depth + 1 , config ) ; err != nil { return } default : if dst . CanSet ( ) && ( ! isEmptyValue ( src ) || overwriteWithEmptySrc ) && ( overwrite || isEmptyValue ( dst ) ) { dst . Set ( src ) } } return }
// Traverses recursively both values, assigning src's fields values to dst.
// The map argument tracks comparisons that have already been seen, which allows
// short circuiting on recursive types.
Traverses recursively both values assigning src s fields values to dst . The map argument tracks comparisons that have already been seen which allows short circuiting on recursive types .