73

What is the way of printing "Foo" here? In this example, what prints is "string".

http://play.golang.org/p/ZnK6PRwEPp

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.Indirect(reflect.ValueOf(a))
    fmt.Println(val.Field(0).Type().Name())
}
sat
  • 5,079
  • 9
  • 60
  • 79

6 Answers6

83

You want val.Type().Field(0).Name. The Field method on reflect.Type will return a struct describing that field, which includes the name, among other information.

There is no way to retrieve the field name for a reflect.Value representing a particular field value, since that is a property of the containing struct.

James Henstridge
  • 39,489
  • 6
  • 120
  • 108
  • "There is no way to retrieve the field name for a reflect.Value representing a particular field value" - Why is that the case? Isn't the type and name part of the field itself? – sat Jun 21 '14 at 00:57
  • @sat As soon as you have the `reflect.Value` of a specific field, it is no different to any other variable. Only the struct has the information about it's fields. – nemo Jun 21 '14 at 01:06
  • 1
    @sat: in your example, `val.Field(0)` is no different to a `reflect.Value` for any other string. It doesn't "remember" that it was part of a struct. – James Henstridge Jun 21 '14 at 01:10
  • @JamesHenstridge - But I don't really need it to remember that it belongs to a struct. All I was trying to print was the name of the variable from the field itself using reflection (whether its part of a struct or not). Sorry if its really a newbie question – sat Jun 21 '14 at 01:30
  • That's the thing: the variable doesn't have a name -- its just a location in memory. – James Henstridge Jun 21 '14 at 01:34
  • So the struct maintains meta information for the name? But a simple variable has none? – sat Jun 21 '14 at 01:42
  • The runtime type information for struct types includes the names and types of its members, yes. – James Henstridge Jun 21 '14 at 01:49
  • Also note that there is no in-memory pointer from the variable `a` to the type `*A`: that is static information. The way the reflect package works is that calling `reflect.ValueOf(a)` involves creating an interface variable holding the `a`. This variable will use `a`'s static type, and that is what is used to do the introspection. – James Henstridge Jun 21 '14 at 01:54
31

You need to Get the Field of the Type Definition not of the Value.

http://play.golang.org/p/7Bc7MJikbJ

package main

import "fmt"
import "reflect"

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.Indirect(reflect.ValueOf(a))
    fmt.Println(val.Type().Field(0).Name)
}
fabrizioM
  • 44,184
  • 15
  • 95
  • 115
26

I think the better way to get the fields' name in the struct is

func main() {
    a := &A{Foo: "afoo"}
    val := reflect.ValueOf(a).Elem()
    for i:=0; i<val.NumField();i++{
        fmt.Println(val.Type().Field(i).Name)
    }
}

There are two tips:

  1. use .Elem() after you reflect.ValueOf(a), because in your case, a is a pointer.
  2. val.Field(i).Type().Name is totally different from val.Type().Field(i).Name. The latter one can get the name of the field in the struct

Hope that it is helpful..

If you want to have a look at more cases, please check my 2mins article

oscarz
  • 916
  • 10
  • 17
24

With the new Names method of the structs package it's even more easier:

package main

import (
    "fmt"

    "github.com/fatih/structs"
)

type A struct {
    Foo string
    Bar int
}

func main() {
    names := structs.Names(&A{})
    fmt.Println(names) // ["Foo", "Bar"]
}
Fatih Arslan
  • 15,241
  • 9
  • 52
  • 53
1

You can also use https://github.com/fatih/structs

// Convert the fields of a struct to a []*Field
fields := s.Fields()

for _, f := range fields {
    fmt.Printf("field name: %+v\n", f.Name())
}
Thellimist
  • 3,199
  • 4
  • 29
  • 47
1
package main

import "fmt"
import "reflect"

type A struct {
    Foo string
}

func (a *A) PrintFoo() {
    fmt.Println("Foo value is " + a.Foo)
}

func main() {
    a := &A{Foo: "afoo"}

    //long and bored code
    t := reflect.TypeOf(*a)
    if t.Kind() == reflect.Struct {
        for i := 0; i < t.NumField(); i++ {
            fmt.Println(t.Field(i).Name)
        }
    } else {
        fmt.Println("not a stuct")
    }

    //shorthanded call
    fmt.Println(reflect.TypeOf(*a).Field(0).Name)//can panic if no field exists

}