在C#或者Java裏面咱們都知道,一個Class是要包含成員變量和方法的,對於GO語言的Struct也同樣,咱們也能夠給Struct定義一系列方法。數組
1、怎麼定義一個方法?函數
Go的方法是在函數前面加上一個接收者,這樣編譯器就知道這個方法屬於哪一個類型了。例如:性能
package demo1 import ( "fmt" ) type Student struct { Name string Age int Class string } func (stu Student) GetUserInfo(student Student) { fmt.Printf("學生姓名:%v 年齡: %v 班級:%v ",student.Name,student.Age,student.Class) }
上面的代碼就是定義了一個Student的結構體,而後針對這個結構體,建立了三個方法。咱們能夠經過【實例名.方法名】的方式來訪問這個結構體內的方法。測試
package main import "Function/demo1" func main(){ student:=demo1.Student{ Name:"XiaoMing", Age:20, Class:"3-2", } student.GetUserInfo(student) }
2、接收者的類型問題spa
上面的GetUserInfo的接收者是一個Student類型,這裏就會出現一個問題,若是我是設定類的操做,那麼不會改變對應實例的值,它只是一個拷貝。下面的例子將說明這個問題,下面這個Set方法接收者是Student指針
type Student struct { Name string Age int Class string } func (stu Student) SetStudentName(name string) { stu.Name = name }
main函數中使用這個類code
func main(){ student:=demo2.Student{ Name:"XiaoMing", Age:20, Class:"3-2", } student.SetStudentName("LiLie") fmt.Printf("Name: %v",student.Name ) }
結果:blog
Name: XiaoMing
能夠看到,這裏並沒把Name進行修改。內存
若是咱們使用Student指針類型做爲接收者,則會修改這個值。例子以下:編譯器
func (stu *Student) SetStudentName(name string) { stu.Name = name //這裏爲何能stu直接.出Name,是Go的語法糖至關於 (*stu).Name }
再次運營結果爲:
Name: LiLie
3、什麼時候使用值類型接收者,什麼時候使用指針類型接收者。
粗暴的結論:若是你不知道怎麼選擇,那就使用指針。但有時候,使用值接收者會更合理,尤爲是效率考慮,好比:不須要修改的小 struct、基礎數據類型。如下是一些有用的指導方針:
- 若是接收者是 map、func 或 chan,不用使用指針。若是是 slice,而且方法不會 reslice 或 從分配 slice,不要使用指針;
- 若是方法須要修改接收者,必須使用指針; - 若是接收者是包含了 sync.Mutex 或相似的同步字段的結構體(struct),接收者必須使用指針,避免拷貝;
- 若是接收者是一個大的結構體或數組,使用指針會更高效。但多大是大?若是全部元素(struct 的字段或數組元素)做爲方法的參數傳遞認爲太大,那麼做爲接收者也是太大。(粗暴一些,全部元素內存超過指針大小,能夠考慮使用指針);
- 若是接收者是結構體、數組或 slice,同時,它們的元素是指針,且指向的數據要改變,那麼使用指針接收者會更合理;(有點繞,那就總原則:用指針沒錯);
- 若是接收者是小的數組,或小的沒有可變字段或指針的結構體,或者結構體字段只是簡單的基礎類型,值接收者會更合理;值接收者能減小垃圾回收的壓力,通常會優先分配在棧上(記住是通常,由於有可能逃逸);但除非有性能測試驗證,不然別由於能夠介紹垃圾回收壓力,就選擇值接收者;
最後再強調一下,若是你拿不定主意,那就用指針接收者。