【问题标题】:Get all the tags of hierarichal struct in Go获取Go中分层结构的所有标签
【发布时间】:2020-01-03 00:06:25
【问题描述】:

我想将我的 Rest 回复中的某些字段从英语翻译成印地语。我有几个翻译文件,其中我有从英语到印地语的单词映射。我想通过字段标签提供的文件的名称。 所以我的结构看起来像这样

    type myResponse struct {
        City string `translatorFile:"CityEToH"`
        State string `translatorFile:"StateEToH"`
        StationCode []string `translatorFile:"StationCodeEToH"`
        InsideStruct insideStruct
    }

    type insideStruct struct {
        trainName string `translatorFile:"TrainEToH"`
        StartingPoint string `translatorFile:"StationCodeEToH"`
        FinishPoint string `translatorFile:"StationCodeEToH"`
    }

我想编写一个通用的翻译方法,它将 interface{} 作为输入参数,并将返回一个接口(在转换输入之后)作为输出。我刚刚开始学习 Go 并且我坚持执行。我无法创建将 fieldName 映射到相应的翻译文件名称的映射类型的结构。

我已经尝试过 reflect.typeOf(input),但是我无法获取 insideStruct 的标签。这只是payload的一个示例结构,我也可以继承4-5级结构。

有没有办法把 fieldName、tags 和 fieldValue 放在一起。或者还有其他更好的方法来实现吗?

【问题讨论】:

  • 显示你到目前为止尝试过的内容。
  • 使用t:=reflect.TypeOf(obj)获取对象的类型,如果是struct,使用fld:=t.FieldByIndex迭代字段,使用fld.Tag.Get访问标签。
  • @CeriseLimón 尝试解组将结构转换为接口(用于解析输入),但我丢失了标签。之后,我尝试编写一个递归方法来迭代输入并在字段和翻译文件之间创建映射。在这种方法中,我将 interface{} 作为输入参数。我正在遍历字段 (reflect.TypeOf(input).NumField()) 并检查类型。对于 string 类型,我将标签详细信息放入 map 中,对于 reflect.Struct 类型,我使用与 reflect.TypeOf(input) 相同的参数调用相同的方法(现在让我们忽略像 slice 这样的其他类型)。这不适用于 insideSt
  • 编写你的递归函数得到一个reflect.Type,这样当你发现结构体字段时就可以轻松调用它。在顶层,使用myFunc(reflect.TypeOf(myStruct{})) 调用它
  • 一个值得检查的技巧是使用 json:"UniqKey" 然后在编组输出上使用 strings.ReplaceAll(marshalOutput, "UniqKey", "HindiKey")。我还认为,与实现标签相比,与基准进行比较是一个良好的开端

标签: go


【解决方案1】:

这是一个遍历值并为每个带有关联结构标记的字符串调用函数的函数:

func walkStrings(v reflect.Value, tag reflect.StructTag, fn func(reflect.Value, reflect.StructTag)) {
    v = reflect.Indirect(v)
    switch v.Kind() {
    case reflect.Struct:
        t := v.Type()
        for i := 0; i < t.NumField(); i++ {
            walkStrings(v.Field(i), t.Field(i).Tag, fn)
        }
    case reflect.Slice, reflect.Array:
        if v.Type().Elem().Kind() == reflect.String {
            for i := 0; i < v.Len(); i++ {
                walkStrings(v.Index(i), tag, fn)
            }
        }
    case reflect.String:
        fn(v, tag)
    }
}

函数fn可以使用Value.String以字符串形式获取值,Value.SetString可以更改值。使用StructTag.Get 获取标签。一个示例函数是:

func translate(v reflect.Value, tag reflect.StructTag) {
    if !v.CanSet() {
        // unexported fields cannot be set
        return
    }
    file := tag.Get("translatorFile")
    if file == "" {
        return
    }
    v.SetString(translatStringWithFile(v.String(), file)
}

调用walkStrings,使用结构指针的reflect.Value和空字符串作为标签:

v := myResponse{
    City:         "mycity",
    StationCode:  []string{"code1", "code2"},
    InsideStruct: insideStruct{"trainname", "start", "finish"},
}
walkStrings(reflect.ValueOf(&v), "", translate)

Run it on the playground.

【讨论】:

    猜你喜欢
    • 2012-03-23
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    相关资源
    最近更新 更多