golang-指针特质

Need help understanding why this breaks. PrintFoo can be called using either pointer or value. Why not NumField?

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

type A struct {
   foo string
}

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

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

        (*a).PrintFoo() //Works - no problem
        a.PrintFoo() //Works - no problem
        reflect.TypeOf(*a).NumField() //Works - no problem - Type = main.A
        reflect.TypeOf(a).NumField() //BREAKS! - Type = *main.A
}

From the documentation :

// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int

You are calling it on a pointer, you have to call it on a struct instead, for example :

fmt.Println(reflect.Indirect(reflect.ValueOf(a)).NumField())
fmt.Println(reflect.Indirect(reflect.ValueOf(*a)).NumField())

When you're not sure if your value is a pointer or not, use reflect.Indirect:

Indirect returns the value that v points to. If v is a nil pointer, Indirect returns a zero Value. If v is not a pointer, Indirect returns v.

//edit:

NumField gets called on Value, not your actual object, for example of you do:

func main() {
    a := &A{foo: "afoo"}
    fmt.Printf("%#v
", reflect.TypeOf(*a))
    fmt.Printf("%#v
", reflect.TypeOf(a))
}

You will get :

//*a
&reflect.rtype{size:0x8, ...... ptrToThis:(*reflect.rtype)(0xec320)} 
//a
&reflect.rtype{size:0x4, ...... ptrToThis:(*reflect.rtype)(nil)}

As you can tell, it's a completely different beast.

  • The first one holds information about the pointer, hence ptrToThis points to the actual struct.
  • The second holds info about the struct itself.