【问题标题】:Go function with dynamic types of structures具有动态结构类型的 Go 函数
【发布时间】:2021-02-07 20:04:34
【问题描述】:

有没有人可以帮助我:我需要为不同类型的结构设置字段值。我有一张从数据库中提取的数据地图。在这个特定的函数中,我想创建一个任何结构的对象,其字段与地图匹配

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 
} 

但是我在这个字符串“reflections.SetField(&obj, n, m[tag])”中得到一个错误 它不起作用,因为“obj”不是结构

非常感谢您的所有回答!

【问题讨论】:

    标签: go struct interface


    【解决方案1】:

    您必须将指向对象的指针传递给您的组合器函数。来自reflections.SetFields的文档:

    obj 参数必须是一个指向结构的指针,否则它会很好 失败。

    所以:

    member := Combiner(fields, &Member{})
    card := Combiner(fields, &CardData{})
    

    Combiner内部:

    reflections.SetField(obj, n, m[tag]) 
    

    【讨论】:

      【解决方案2】:

      您已接近正确的解决方案。代码的问题是:

      • 字符串引号字符是",而不是'
      • 标准结构字段标记中的冒号后没有空格。
      • 无法设置非导出字段。
      • 要在字段上设置值,反射值必须具有可寻址值。

      这是修复问题的代码:

      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!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-11
        • 1970-01-01
        • 2021-06-02
        • 2020-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多