Question

Is it possible to reflect on a field of a struct, and get a reference to its tag values?

For example:

type User struct {
    name    string `json:name-field`
    age     int
}
// ...
user := &User{"John Doe The Fourth", 20}
getStructTag(user.name)
// ...
func getStructTag(i interface{}) string{
   //get tag from field
   
}

From what I can see, the usual way to do this is to range over typ.NumField(), and then call field.Tag.Get("tagname").

However, in my use-case, it would be much better to not have to pass the whole struct in.

Était-ce utile?

La solution

You don't need to pass in the whole struct, but passing in the value of one of the fields is not sufficient.

In your example user.name field is just a string - the reflect package will have no way of correlating that back to the original struct.

Instead, you need to pass around the reflect.StructField for the given field:

field, ok := reflect.TypeOf(user).Elem().FieldByName("name")
…
tag = string(field.Tag)

Note: we use Elem above because user is a pointer to a struct.

You can play with an example here.

Autres conseils

Modifying the above answer can give value of a specific tag

package main

import (
    "fmt"
    "reflect"
)

type User struct {
    Name string `json:"name_field"`
    Age  int
}

func main() {
    user := &User{"John Doe The Fourth", 20}

    field, ok := reflect.TypeOf(user).Elem().FieldByName("Name")
    if !ok {
        panic("Field not found")
    }
    fmt.Println(getStructTag(field, "json")) //name_field
}

func getStructTag(f reflect.StructField, tagName string) string {
    return string(f.Tag.Get(tagName))
}

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

Clean way to list all tags from a struct (using external lib).

External lib: https://github.com/fatih/structs

Example: https://go.dev/play/p/C_yXMdbFYAq

package main

import (
    "fmt"

    "github.com/fatih/structs"
)

type User struct {
    Name string `json:"name_field"`
    Age  int    `json:"age_field"`
}

func main() {
    user := &User{}
    fields := structs.Fields(user)

    for _, field := range fields {
        tag := field.Tag("json")
        fmt.Println(tag)
    }
}

Result:

name_field
age_field
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top