Reputation: 25
Does anybody can help me with it: I need to set up field values for different types of structures. I have a map with data, extracted from the database. In this particular function, I want to create an object of any structure, fields of which are matched with the map
type Member struct {
firstName string `xml: "FIRST_NAME"`
lastName string `xml: "LAST_NAME"`
}
type CardData struct {
cardType string `xml: "CARD_TYPE"`
cardNumber string `xml: "CARD_NUMBER"`
}
func main() {
fields := make(map[string]string)
fields['CARD_TYPE'] = "VISA"
fields['FIRS_NAME'] = "Aria Stark"
member := Combiner(fields, Member{})
card := Combiner(fields, CardData{})
}
func Combiner(m map[string]string, obj interface{}) interface{} {
ff := reflect.ValueOf(obj)
typeOfS := ff.Type()
for i := 0; i< ff.NumField(); i++ {
tag := typeOfS.Field(i).Tag.Get("xml")
if _, ok := m[tag]; ok {
n := typeOfS.Field(i).Name
reflections.SetField(&obj, n, m[tag])
} else {
fmt.Printf("The field %s is not found \n", tag)
}
}
return obj
}
but I get an error in this string "reflections.SetField(&obj, n, m[tag])" It doesn't work because "obj" is not a struct
Many thanks for all yours answers!
Upvotes: 0
Views: 263
Reputation:
You are close to a correct solution. The problems with the code are:
"
, not '
.Here's the code with the problems fixed:
type Member struct {
// NOTE: Export by capitalizing first letter in field name.
// NOTE: Remove space after the :
FirstName string `xml:"FIRST_NAME"`
LastName string `xml:"LAST_NAME"`
}
type CardData struct {
CardType string `xml:"CARD_TYPE"`
CardNumber string `xml:"CARD_NUMBER"`
}
func main() {
fields := make(map[string]string)
// NOTE: use " instead of '
fields["CARD_TYPE"] = "VISA"
fields["FIRST_NAME"] = "Aria Stark"
// NOTE: Pass pointer to struct so that combiner
// has an addressable value.
member := Combiner(fields, &Member{})
card := Combiner(fields, &CardData{})
fmt.Println(member)
fmt.Println(card)
}
func Combiner(m map[string]string, obj interface{}) interface{} {
// NOTE: dereference the pointer by calling Elem()
ff := reflect.ValueOf(obj).Elem()
typeOfS := ff.Type()
for i := 0; i < ff.NumField(); i++ {
tag := typeOfS.Field(i).Tag.Get("xml")
if _, ok := m[tag]; ok {
// NOTE: Set the field directly using the reflect package.
ff.Field(i).Set(reflect.ValueOf(m[tag]))
} else {
fmt.Printf("The field %s is not found \n", tag)
}
}
return obj
}
Run the program on the Playground!
Upvotes: 1
Reputation: 31269
You have to pass a pointer to the object to your Combiner function. From the documentation of reflections.SetFields
:
obj param has to be a pointer to a struct, otherwise it will soundly fail.
So:
member := Combiner(fields, &Member{})
card := Combiner(fields, &CardData{})
and inside Combiner
:
reflections.SetField(obj, n, m[tag])
Upvotes: 1