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)) // 第一個返回值類型 } }