Created
April 25, 2019 10:15
-
-
Save fenos/ddeac979a9d65c653b5c3684aacd70c1 to your computer and use it in GitHub Desktop.
Merge 2 generic structs values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package structs | |
import "reflect" | |
// obj1 := struct{ ID string Name string } | |
// obj2 := struct{ ID string Name string }{ ID: "1", Name: "Jhon" } | |
// | |
// merged := merge.Structs(obj1, obj2) | |
// | |
// merge => struct{ ID string Name string }{ ID: "1", Name: "Jhon" } | |
// | |
func Structs(baseStruct interface{}, fromValues interface{}) interface{} { | |
fieldNames := getFieldsName(baseStruct) | |
pointerBaseStruct := interfacePointer(baseStruct) | |
fromPtr := interfacePointer(fromValues) | |
for parentIndex, fieldName := range fieldNames { | |
keyIndex := hasKey(fieldName, fromValues) | |
if keyIndex != -1 { | |
setInterfaceValue( | |
reflect.Indirect(pointerBaseStruct).Field(parentIndex), | |
reflect.Indirect(fromPtr).Field(keyIndex), | |
) | |
} | |
} | |
return pointerBaseStruct.Elem().Interface() | |
} | |
func getFieldsName(a interface{}) ( fields []string ) { | |
val := interfacePointer(a) | |
elem := val.Elem() | |
for i:=0; i<elem.NumField();i++{ | |
fields = append(fields, elem.Type().Field(i).Name) | |
} | |
return fields | |
} | |
// https://stackoverflow.com/a/14162161/2138322 | |
func interfacePointer(data interface{}) reflect.Value { | |
var ptr reflect.Value | |
value := reflect.ValueOf(data) | |
if value.Type().Kind() == reflect.Ptr { | |
ptr = value | |
value = ptr.Elem() // acquire value referenced by pointer | |
} else { | |
ptr = reflect.New(reflect.TypeOf(data)) // create new pointer | |
temp := ptr.Elem() // create variable to value of pointer | |
temp.Set(value) // set value of variable to our passed in value | |
} | |
return ptr | |
} | |
func setInterfaceValue(baseStruct reflect.Value, fromStruct reflect.Value) { | |
baseStruct.Set(fromStruct) | |
} | |
func hasKey(key string, object interface{}) int { | |
fields := getFieldsName(object) | |
for index, fieldName := range fields { | |
if fieldName == key { | |
return index | |
} | |
} | |
return -1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment