Golang获取特定结构字段名称的字符串表示

时间:2017-05-04 19:44:02

标签: go reflection field-names

我真的想要一种在go中打印字段名称的字符串表示的方法。它有几个用例,但这是一个例子:

假设我有一个结构

type Test struct {
    Field      string `bson:"Field" json:"field"`
    OtherField int    `bson:"OtherField" json:"otherField"`
}

,例如,我想做一个mongo find:

collection.Find(bson.M{"OtherField": someValue})

我不喜欢我必须把字符串“OtherField”放在那里。它似乎很脆弱,容易错误排序或更改结构,然后我的查询失败,而我不知道它。

有没有办法获得字符串“OtherField”而不必声明const或类似的东西?我知道我可以使用反射来获取结构中的字段名称列表,但我真的想要按照

的方式做一些事情。
fieldName := nameOf(Test{}.OtherField) 
collection.Find(bson.M{fieldName: someValue})

有没有办法在Go中做到这一点? C#6有内置的名称,但通过反思我无法在Go中找到任何方法。

2 个答案:

答案 0 :(得分:6)

我真的不认为有。您可以通过反射加载一组类型,并为字段名称生成一组常量。所以:

ws://localhost:5678

可以生成如下内容:

type Test struct {
    Field      string `bson:"Field" json:"field"`
    OtherField int    `bson:"OtherField" json:"otherField"`
}

您可以使用var TestFields = struct{ Field string OtherField string }{"Field","OtherField"} 作为常量。

不幸的是,我不知道有任何类似的现有工具。这样做很简单,但最后连接到TestFields.Field

修改

我如何生成它:

  1. 制作一个接受go generatereflect.Type数组的软件包并吐出代码文件。
  2. 使用main函数在我的repo中的某处创建interface{}

    generate.go
  3. func main(){ var text = mygenerator.Gen(Test{}, OtherStruct{}, ...) // write text to constants.go or something } 添加到我的主应用并运行//go:generate go run scripts/generate.go

答案 1 :(得分:1)

这是一个函数,它将返回带有struct字段名称的[]string。我认为它是按照它们的定义顺序出现的。

警告:重新排序结构定义中的字段会改变它们出现的顺序

https://play.golang.org/p/dNATzNn47S

package main

import (
    "fmt"
    "strings"
    "regexp"
    )

type Test struct {
    Field      string `bson:"Field" json:"field"`
    OtherField int    `bson:"OtherField" json:"otherField"`
}

func main() {
    fields, err := GetFieldNames(Test{})
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(fields)
}


func GetFieldNames(i interface{}) ([]string, error) {
    // regular expression to find the unquoted json
    reg := regexp.MustCompile(`(\s*?{\s*?|\s*?,\s*?)(['"])?(?P<Field>[a-zA-Z0-9]+)(['"])?:`)

    // print struct in almost json form (fields unquoted)
    raw := fmt.Sprintf("%#v", i)

    // remove the struct name so string begins with "{"
    fjs := raw[strings.Index(raw,"{"):]

    // find and grab submatch 3
    matches := reg.FindAllStringSubmatch(fjs,-1)

    // collect
    fields := []string{}
    for _, v := range matches {
        if len(v) >= 3 && v[3] != "" {
            fields = append(fields, v[3])
        }

    }


return fields, nil

}