【问题标题】:Couldn't unmarshal xml to a dynamically created struct using reflection in Golang无法使用 Golang 中的反射将 xml 解组为动态创建的结构
【发布时间】:2021-05-27 10:27:17
【问题描述】:

这是我解析 xml 的代码。在函数结束时,我应该在值切片中包含结构的字段值。

func FindAttrs(attrs []Tag, errorChan chan<- error) {
    var tableFields []reflect.StructField
    for _, v := range attrs {
        tableFields = append(tableFields, reflect.StructField{
            Name:      strings.Title(v.Name),
            Type:      reflect.TypeOf(""),
            Tag:       reflect.StructTag(fmt.Sprintf(`xml:"%v,attr"`, v.Name)),
            Offset:    0,
            PkgPath:   "utility",
            Index:     nil,
            Anonymous: false,
        })
    }
    unmarshalStruct := reflect.Zero(reflect.StructOf(tableFields))
    err := xml.Unmarshal(ReadBytes(errorChan), &unmarshalStruct)
    HandleError(err, "Error parse config", false, errorChan)
    values := make([]interface{}, unmarshalStruct.NumField())
    for i := 0; i < unmarshalStruct.NumField(); i++ {
        values[i] = unmarshalStruct.Field(0).Interface()
    }
}

但是,它会因以下消息而恐慌:

reflect.Value.Interface: cannot return value obtained from unexported field or method

我称之为:

utility.FindAttrs([]utility.Tag{
        {"name", reflect.String}, {"isUsed", reflect.String},
    }, errorChan)

我的xml是&lt;configuration name="mur" isUsed="mur"/&gt;

【问题讨论】:

  • "cannot return value getting from unexported field" -- 意味着你要么必须导出字段,要么不做你想做的事做。
  • 字段我是大写的,你可以在代码中看到。
  • 我的错,我现在看到您正在使用 strings.Title。但是您的代码存在多个问题: 1. 删除字段的 PkgPath,用于未导出的字段。 2.你解组到*reflect.Value而不是生成的结构类型,这不会像你期望的那样,即字段 Name 和 IsUsed 不会被 unmarshal 填充,因为它们不是反射的字段.Value 结构类型。 3. 你总是将第 0 个字段传递给循环中的第 i 个值。可能还有其他我没有发现的错误。
  • reflect.Zero 返回一个reflect.Valuereflect.Value 是基础值的通用表示,它不是实际值。所以&amp;unmrshalStruct 属于*reflect.Value 类型,它不是属于你想要和需要的*struct { Name string, IsUsed string } 类型。

标签: xml go struct reflection


【解决方案1】:

需要创建一个指向结构而不是值的指针,并将指针的值(可以通过检索Interface() 函数)传递给 Unmarshal 而不是它本身。

var tableFields []reflect.StructField
    for _, v := range attrs {
        tableFields = append(tableFields, reflect.StructField{
            Name: strings.Title(v.Name),
            Type: reflect.TypeOf(""),
            Tag:  reflect.StructTag(fmt.Sprintf(`xml:"%v,attr"`, v.Name)),
        })
    }

    rv := reflect.New(reflect.StructOf(tableFields)) // initialize a pointer to the struct

    v := rv.Interface() // get the actual value
    err := xml.Unmarshal([]byte(`<configuration name="foo" isUsed="bar"/>`), v)
    if err != nil {
        panic(err)
    }

    rv = rv.Elem() // dereference the pointer
    values := make([]interface{}, rv.NumField())
    for i := 0; i < rv.NumField(); i++ {
        values[i] = rv.Field(i).Interface()
    }

【讨论】:

    猜你喜欢
    • 2015-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 2018-12-27
    • 2018-07-16
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多