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.

+3


source to share


2 answers


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

    or interface{}

    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

+6


source


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

      

}

+1


source







All Articles