Golang get string representation of specific struct field name
I really need a way to print the string representation of a field name in go. It has several use cases, but here's an example:
lets say i have a structure
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
and for example I want to find mongo find:
collection.Find(bson.M{"OtherField": someValue})
I don't like that I need to put the "OtherField" line in there. Seems brittle and easy to either buggy or restructure and then my request completes without my knowledge.
Is there a way to get the string "OtherField" without having to declare a constant or something? I know I can use reflection to get a list of field names from a struct, but I'd really like to do something in strings
fieldName := nameOf(Test{}.OtherField)
collection.Find(bson.M{fieldName: someValue})
Is there a way to do this in Go ?? C # 6 has a built-in nameof, but digging into reflection I can't seem to find a way to do this in Go.
source to share
I really don't think there is. You can load a set of types through reflection and generate a set of constants for field names. So:
type Test struct {
Field string `bson:"Field" json:"field"`
OtherField int `bson:"OtherField" json:"otherField"`
}
Can generate something like:
var TestFields = struct{
Field string
OtherField string
}{"Field","OtherField"}
and you can use TestFields.Field
as a constant.
Unfortunately, I don't know of any existing tool that does something like this. It would be pretty straightforward to do and connect before go generate
though.
EDIT:
How I generated it:
- Make a package that takes an array
reflect.Type
orinterface{}
and spits out a code file. -
Do
generate.go
somewhere in my repo with the 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 main application and rungo generate
source to share
Here is a function that will return []string
the names of the structure fields. I think it happens in the order they are defined.
WARNING. Reordering fields in a structure 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
}
source to share