英文:
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"`
}
例如,我想要进行一个MongoDB的查找操作:
collection.Find(bson.M{"OtherField": someValue})
我不喜欢在这里放入字符串"OtherField"。它似乎很脆弱,容易出错,或者当结构体发生变化时,我的查询会失败而我却不知道。
有没有办法在不声明常量或类似的东西的情况下获取字符串"OtherField"?我知道可以使用反射从结构体中获取字段名列表,但我真的想做类似这样的事情:
fieldName := nameOf(Test{}.OtherField)
collection.Find(bson.M{fieldName: someValue})
在Go语言中有没有办法做到这一点?C# 6中有内置的nameof
,但是在Go语言中,通过反射我找不到任何方法来实现这一点。
英文:
I really want a way to print the string representation of a field name in go. It has several use cases, but here is an example:
lets say I have a struct
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
and, for example, I want to do a mongo find:
collection.Find(bson.M{"OtherField": someValue})
I don't like that I have to put the string "OtherField" in there. It seems brittle and easy to either misstype or have the struct change and then my query fails without me knowing it.
Is there any way to get the string "OtherField" without having to either declare a const or something like that? I know I can use reflection to a get a list of field names from a struct, but I'd really like to do something along the lines of
fieldName := nameOf(Test{}.OtherField)
collection.Find(bson.M{fieldName: someValue})
is there any way to do this in Go?? C# 6 has the built in nameof, but digging through reflection I can't find any way to do this in Go.
答案1
得分: 7
我不认为有这样的工具。你可以通过反射加载一组类型,并为字段名称生成一组常量。例如:
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{}
的数组,并输出一个代码文件。 -
在我的代码库中的某个地方创建一个
generate.go
文件,其中包含主函数:func main() { var text = mygenerator.Gen(Test{}, OtherStruct{}, ...) // 将文本写入constants.go或其他文件 }
-
在我的主应用程序中添加
//go:generate go run scripts/generate.go
,然后运行go generate
命令。
英文:
I don't really think there is. You may be able to load a set of types via reflection and generate a set of constants for the field names. So:
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
Could generate something like:
var TestFields = struct{
Field string
OtherField string
}{"Field","OtherField"}
and you could use TestFields.Field
as a constant.
Unfortunately, I don't know of any existing tool that does anything like that. Would be fairly simple to do, and wire up to go generate
though.
EDIT:
How I'd generate it:
-
Make a package that accepts an array of
reflect.Type
orinterface{}
and spits out a code file. -
Make a
generate.go
somewhere in my repo with main function:func main(){ var text = mygenerator.Gen(Test{}, OtherStruct{}, ...) // write text to constants.go or something }
-
Add
//go:generate go run scripts/generate.go
to my main app and rungo generate
答案2
得分: 1
这是一个函数,它将返回一个[]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) {
// 用于查找未引用的json的正则表达式
reg := regexp.MustCompile(`(\s*?{\s*?|\s*?,\s*?)(['"])?(?P<Field>[a-zA-Z0-9]+)(['"])?:`)
// 以几乎json的形式打印结构体(字段未引用)
raw := fmt.Sprintf("%#v", i)
// 删除结构体名称,使字符串以"{"开头
fjs := raw[strings.Index(raw,"{"):]
// 查找并获取子匹配项3
matches := reg.FindAllStringSubmatch(fjs,-1)
// 收集字段
fields := []string{}
for _, v := range matches {
if len(v) >= 3 && v[3] != "" {
fields = append(fields, v[3])
}
}
return fields, nil
}
希望对你有帮助!
英文:
Here is a function that will return a []string
with the struct field names. I think it comes in the order they are defined.
WARNING: Reordering the fields in the struct definition will change the order in which they appear
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论