0

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!

2 Answers 2

1

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]) 
Sign up to request clarification or add additional context in comments.

Comments

1

You are close to a correct solution. The problems with the code are:

  • The string quote character is ", not '.
  • There is no space after the colon in standard struct field tags.
  • Non-exported fields cannot be set.
  • To set a value on a field, the reflect value must have an addressable value.

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!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.