Skip to content

Instantly share code, notes, and snippets.

@Faheetah
Last active September 29, 2021 19:26
Show Gist options
  • Save Faheetah/eb1cbd6b1262ddb404e07062a3936879 to your computer and use it in GitHub Desktop.
Save Faheetah/eb1cbd6b1262ddb404e07062a3936879 to your computer and use it in GitHub Desktop.
Golang: pass in a struct and a map and retrieve values

This is handy for cases such as needing to dynamically assign structs, for example when use with marshalling or when assigning the results of a SQL query into a struct, without duplicating code for each type. This is a naive implementation as it takes absolutely no error checking into account. It is not production safe and is meant to demonstrate how to iterate through and populate a struct.

Example usage

type Foo struct {
	Int        int
	String     string
	Unassigned string
}

func main() {
	foo := &Foo{}

	values := map[string]interface{}{
		"int":    11,
		"string": "foo",
	}

	assignStructValues(foo, values)
	fmt.Println(foo.Int) // 11
	fmt.Println(foo.String) // foo
	fmt.Println(foo.Unassigned) // still default ""
	
	// note that we still need to assert the value with .(Foo) when we get it back
	// if we were dealing with arrays of structs we could cast with .([]Foo)
	newFoo := assignNewStruct(foo, values)
	fmt.Println(newFoo.(Foo).Int) // 11
}
// Modifying the struct in place
func assignStructValues(structInterface interface{}, values map[string]interface{}) {
structType := reflect.TypeOf(structInterface).Elem()
structValue := reflect.ValueOf(structInterface)
for i := 0; i < structType.NumField(); i++ {
fieldName := strings.ToLower(structType.Field(i).Name)
if val, ok := values[fieldName]; ok {
newValue := reflect.ValueOf(val)
structValue.Elem().Field(i).Set(newValue)
}
}
}
// Returning a new instance
func assignNewStruct(structInterface interface{}, values map[string]interface{}) interface{} { // set interface{} as return type
structType := reflect.TypeOf(structInterface).Elem()
structValue := reflect.New(structType) // using reflect.New instead of reflect.ValueOf
for i := 0; i < structType.NumField(); i++ {
fieldName := strings.ToLower(structType.Field(i).Name)
if val, ok := values[fieldName]; ok {
newValue := reflect.ValueOf(val)
structValue.Elem().Field(i).Set(newValue)
}
}
return reflect.Value(structValue).Elem().Interface() // and returning a new value instead of no return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment