天天看點

在Go中什麼時候使用指針?

1 在方法中使用指針

什麼是receiver?

func (t T) method_name(t T){}      

這裡面的T就是receiver

  • 使用receiver作為方法參數
func main() {
   r := receiver{Name: "zs"}
   fmt.Println(r)
   r.methodA()
   fmt.Println(r)
}

type receiver struct {
   Id   int
   Name string
   Age  int
}

func (receiver receiver) methodA() {
   receiver.Name = "ls"
}

func (receiver *receiver) methodB() {
   receiver.Name = "ls"
}      

結果:

{0 zs 0}

{0 zs 0}

  • 使用*receiver作為方法參數
func main() {
   r := receiver{Name: "zs"}
   fmt.Println(r)
   r.methodB()
   fmt.Println(r)
}

type receiver struct {
   Id   int
   Name string
   Age  int
}

func (receiver receiver) methodA() {
   receiver.Name = "ls"
}

func (receiver *receiver) methodB() {
   receiver.Name = "ls"
}      

結果:

{0 zs 0}

{0 ls 0}

2 在結構體中使用指針

  • 方式一
func main() {
   student := Student{Map: map[string]int{"S": 0}, ReceiverA: receiver{Name: "A"}, ReceiverB: &receiver{Name: "B"}}
   fmt.Println(student, *student.ReceiverB)
   student.updateA()
   fmt.Println(student, *student.ReceiverB)
}

type receiver struct {
   Id   int
   Name string
   Age  int
}

type Student struct {
   No        int
   Map       map[string]int
   ReceiverA receiver
   ReceiverB *receiver
}

func (stu Student) updateA() {
   stu.Map["a"] = 1
   stu.ReceiverA = receiver{Name: "ww"}
   stu.ReceiverB = &receiver{Name: "ww"}
}

func (stu *Student) updateB() {
   stu.Map["b"] = 2
   stu.ReceiverA = receiver{Name: "ww"}
   stu.ReceiverB = &receiver{Name: "ww"}
}      

結果:

{0 map[S:0] {0 A 0} 0xc0000b4000} {0 B 0}

{0 map[S:0 a:1] {0 A 0} 0xc0000b4000} {0 B 0}

  • 方式二
func main() {
   student := Student{Map: map[string]int{"S": 0}, ReceiverA: receiver{Name: "A"}, ReceiverB: &receiver{Name: "B"}}
   fmt.Println(student, *student.ReceiverB)
   student.updateA()
   fmt.Println(student, *student.ReceiverB)
}

type receiver struct {
   Id   int
   Name string
   Age  int
}

type Student struct {
   No        int
   Map       map[string]int
   ReceiverA receiver
   ReceiverB *receiver
}

func (stu Student) updateA() {
   stu.Map["a"] = 1
   stu.ReceiverA = receiver{Name: "ww"}
   stu.ReceiverB = &receiver{Name: "ww"}
}

func (stu *Student) updateB() {
   stu.Map["b"] = 2
   stu.ReceiverA = receiver{Name: "ww"}
   stu.ReceiverB = &receiver{Name: "ww"}
}      

結果:

{0 map[S:0] {0 A 0} 0xc0000b4000} {0 B 0}

{0 map[S:0 b:2] {0 ww 0} 0xc0000b4060} {0 ww 0}

3 什麼時候使用指針

一個函數何時該用指針類型做receiver對初學者而言一直是個頭疼的問題。下面是列舉了一些常用的判斷指導。

  • 如果receiver是​

    ​map​

    ​​、​

    ​func​

    ​​或者​

    ​chan​

    ​,不要使用指針
  • 如果receiver是​

    ​slice​

    ​并且該函數并不會修改此slice,不要使用指針
  • 如果該函數會修改receiver,此時一定要用指針
  • 如果receiver是​

    ​struct​

    ​​并且包含互斥類型​

    ​sync.Mutex​

    ​,或者是類似的同步變量,receiver必須是指針,這樣可以避免對象拷貝
  • 如果receiver是較大的​

    ​struct​

    ​​或者​

    ​array​

    ​,使用指針則更加高效。多大才算大?假設struct内所有成員都要作為函數變量傳進去,如果覺得這時資料太多,就是struct太大
  • 如果receiver是​

    ​struct​

    ​​,​

    ​array​

    ​​或者​

    ​slice​

    ​,并且其中某個element指向了某個可變量,則這個時候receiver選指針會使代碼的意圖更加明顯
  • 如果receiver使較小的​

    ​struct​

    ​​或者​

    ​array​

    ​​,并且其變量都是些不變量、常量,例如​

    ​time.Time​

    ​,value receiver更加适合,因為value receiver可以減少需要回收的垃圾量。
  • 最後,如果不确定用哪個,使用指針類的receiver

參考文章:

繼續閱讀