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.

Was it helpful?

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.

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top