golang中,struct的method的形式以下:java
func (r ReceiverType) funcName(parameters) (results)c++
若是想要修改struct的成员的值,method被定义时候其ReceiverType必须是struct*形式。若是ReceiverType是struct,则没法改变struct成员的值。golang
废话少说,代码验证:函数
package main import ( "fmt" ) type tag struct { value int32 } func (t tag) Change() { t.value = int32(987) } // The method set of any other named type T consists of all methods with receiver type T. // The method set of the corresponding pointer type *T is the set of all methods with // receiver *T or T (that is, it also contains the method set of T). // 定义receiver的method的时候,通常receiver使用指针形式,由于T也能够调用T*的函数,并可否修改器成员 // 编译器会参考上面的函数隐式的生成下面的函数 // func (t *tag) Change() { // t.value = int32(987) // } type tag2 struct { value int32 } func (t *tag2) Change() { t.value = int32(987) } func main() { // tag* tp := new(tag) tp.value = 123 tp.Change() fmt.Println(tp) // &{123} // tag var tv = *tp tv.Change() fmt.Println(tv) // {123} // tag2 tv2 := tag2{41} tv2.Change() fmt.Println(tv2) // {987} // tag2* var tp2 = &tag2{value: 123} tp2.Change() fmt.Println(tp2) // &{987} }
上面main函数中,第一段代码中对象 tp 的形式为*tag,可是其方法Change没法改变其value值。第二段代码中对象 tv2 的形式为tag2,可是其方法Change却能够改变其value值。this
若是有人感兴趣,我就接着给说道说道。spa
golang中的method的第一个参数就是它的Receiver Type,能够是值形式也能够是指针形式,而c++以及其同类语言java等C系语言中method的方法默认是class* this。也就是说,golang中method有传对象值与传对象地址的值两种,而C系语言强制要求传递对象的地址。最终改变对象值与否取决于Receiver Type,而不取决于 object Variable Type。指针
这么说,就能够理解了吧?Golang中若是函数须要改变对象成员的值,须要Receiver Type为指针形式,若非必要则不要使用指针形式,由于指针形式的对象会被分配在内存堆上,耗费GC资源。code
再补充两个代码示例:对象
example1:内存
/****************************************************** # DESC : # AUTHOR : Alex Stocks # MOD : 2016-09-05 07:26 # FILE : value_ptr_receiver.go ******************************************************/ package main type tag struct { } func (this *tag) String() { println("hello") } type Tag struct { } func (this Tag) String() { println("hello") } func main() { var t tag t.String() var tt *Tag = &Tag{} (*tt).String() }
example2:
type T struct { A int // A is name, int is type, T.A is interface B string } /* 从test例子能够看出,func (this T) GetTName(str string) string有一个隐式的函数: func (this *T) GetTName(str string) string */ func (this T) GetTName(str string) string { this.B = str return this.B } func (this *T) GetName(str string) string { this.B = str return this.B } func test_field_method() { t := T{203, "mh203"} // s := reflect.ValueOf(&t).Elem() // s := reflect.ValueOf(t) s := reflect.Indirect(reflect.ValueOf(t)) // 上面三行等价 typeOfT := s.Type() /* 0: A int = 203 1: B string = mh203 */ for i := 0; i < s.NumField(); i++ { f := s.Field(i) fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) } /* idx: 0 func(main.T, string) string GetTName NumIn: 2 in(0) type: main.T in(1) type: string NumOut: 1 out(1) type: string */ for m := 0; m < reflect.TypeOf(t).NumMethod(); m++ { fmt.Println("idx:", m) method := reflect.TypeOf(t).Method(m) fmt.Println(method.Type) // func(*main.MyStruct) string fmt.Println(method.Name) // GetName fmt.Println("NumIn:", method.Type.NumIn()) // 参数个数 fmt.Println("in(0) type:", method.Type.In(0)) // 参数类型 fmt.Println("in(1) type:", method.Type.In(1)) // 参数类型 fmt.Println("NumOut:", method.Type.NumOut()) // 返回值个数 fmt.Println("out(1) type:", method.Type.Out(0)) // 第一个返回值类型 } /* idx: 0 func(*main.T, string) string GetName NumIn: 2 in(0) type: *main.T in(1) type: string NumOut: 1 out(1) type: string idx: 1 func(*main.T, string) string GetTName NumIn: 2 in(0) type: *main.T in(1) type: string NumOut: 1 out(1) type: string */ for m := 0; m < reflect.TypeOf(&t).NumMethod(); m++ { fmt.Println("idx:", m) method := reflect.TypeOf(&t).Method(m) fmt.Println(method.Type) // func(*main.MyStruct) string fmt.Println(method.Name) // GetName fmt.Println("NumIn:", method.Type.NumIn()) // 参数个数 fmt.Println("in(0) type:", method.Type.In(0)) // 参数类型 fmt.Println("in(1) type:", method.Type.In(1)) // 参数类型 fmt.Println("NumOut:", method.Type.NumOut()) // 返回值个数 fmt.Println("out(1) type:", method.Type.Out(0)) // 第一个返回值类型 } }