Golang 获取特定结构字段名称的字符串表示
Golang get string representation of specific struct field name
我真的想要一种在 go 中打印字段名称的字符串表示形式的方法。它有几个用例,但这里有一个例子:
假设我有一个结构
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
例如,我想做一个 mongo 查找:
collection.Find(bson.M{"OtherField": someValue})
我不喜欢我必须将字符串 "OtherField" 放在那里。错误输入或结构更改似乎很脆弱且容易,然后我的查询在我不知情的情况下失败。
有没有什么方法可以获取字符串 "OtherField" 而不必声明 const 或类似的东西?我知道我可以使用反射从结构中获取字段名称列表,但我真的很想按照
的方式做一些事情
fieldName := nameOf(Test{}.OtherField)
collection.Find(bson.M{fieldName: someValue})
在 Go 中有什么方法可以做到这一点吗? C# 6 具有内置的 nameof,但通过反射挖掘我找不到在 Go 中执行此操作的任何方法。
我真的不认为有。您可以通过反射加载一组类型,并生成 一组字段名称常量。所以:
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
作为常量。
遗憾的是,我不知道有任何现有工具可以执行类似的操作。做起来相当简单,不过连接到 go generate
。
编辑:
我如何生成它:
- 制作一个包,接受
reflect.Type
或 interface{}
的数组并吐出一个代码文件。
在我的 repo 的某个地方创建一个 generate.go
主要功能:
func main(){
var text = mygenerator.Gen(Test{}, OtherStruct{}, ...)
// write text to constants.go or something
}
- 将
//go:generate go run scripts/generate.go
添加到我的主应用程序和 运行 go generate
这是一个函数,它将 return 一个 []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
}
我真的想要一种在 go 中打印字段名称的字符串表示形式的方法。它有几个用例,但这里有一个例子:
假设我有一个结构
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
例如,我想做一个 mongo 查找:
collection.Find(bson.M{"OtherField": someValue})
我不喜欢我必须将字符串 "OtherField" 放在那里。错误输入或结构更改似乎很脆弱且容易,然后我的查询在我不知情的情况下失败。
有没有什么方法可以获取字符串 "OtherField" 而不必声明 const 或类似的东西?我知道我可以使用反射从结构中获取字段名称列表,但我真的很想按照
的方式做一些事情fieldName := nameOf(Test{}.OtherField)
collection.Find(bson.M{fieldName: someValue})
在 Go 中有什么方法可以做到这一点吗? C# 6 具有内置的 nameof,但通过反射挖掘我找不到在 Go 中执行此操作的任何方法。
我真的不认为有。您可以通过反射加载一组类型,并生成 一组字段名称常量。所以:
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
作为常量。
遗憾的是,我不知道有任何现有工具可以执行类似的操作。做起来相当简单,不过连接到 go generate
。
编辑:
我如何生成它:
- 制作一个包,接受
reflect.Type
或interface{}
的数组并吐出一个代码文件。 在我的 repo 的某个地方创建一个
generate.go
主要功能:func main(){ var text = mygenerator.Gen(Test{}, OtherStruct{}, ...) // write text to constants.go or something }
- 将
//go:generate go run scripts/generate.go
添加到我的主应用程序和 运行go generate
这是一个函数,它将 return 一个 []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
}