golang – 指针的特殊性

huangapple go评论93阅读模式
英文:

golang - Pointer idiosyncrasies

问题

需要帮助理解为什么这段代码会出错。PrintFoo可以使用指针或值来调用。为什么NumField不行?

type A struct {
   foo string
}

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

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

        (*a).PrintFoo() //可以正常工作
        a.PrintFoo() //可以正常工作
        reflect.TypeOf(*a).NumField() //可以正常工作 - Type = main.A
        reflect.TypeOf(a).NumField() //出错!- Type = *main.A
}

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

英文:

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
}

答案1

得分: 5

根据文档

// NumField 返回结构体 v 中的字段数量。
// 如果 v 的类型不是 Struct,会引发 panic。
func (v Value) NumField() int

你正在对一个指针进行调用,你需要对一个结构体进行调用,例如示例

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

当你不确定你的值是指针还是其他类型时,可以使用reflect.Indirect

Indirect 返回 v 指向的值。如果 v 是一个空指针,Indirect 返回一个零值。如果 v 不是指针,Indirect 返回 v。

//编辑:

NumField 是在 Value 上调用的,而不是你的实际对象,例如如果你这样做:

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

你会得到:

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

可以看出,它们是完全不同的。

  • 第一个持有指针的信息,因此 ptrToThis 指向实际的结构体。
  • 第二个持有结构体本身的信息。
英文:

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\n", reflect.TypeOf(*a))
	fmt.Printf("%#v\n", 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.

huangapple
  • 本文由 发表于 2014年6月21日 06:26:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/24336537.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定