1. 程式人生 > 程式設計 >深入理解 Golang 指標

深入理解 Golang 指標

Go中一切都通過值傳遞,也就是說,一個函式總是得到值傳遞的副本,總是會分配一個值的副本給函式引數。例如

  • 將int值傳遞的是int值的副本;
  • 指標傳遞指標的副本,而不是指標指向的資料;
  • map 和 slice 值類似於指標,他們是指向底層儲存資料結構的指標,複製map、slice的值,便不會複製他們指向的資料。具體原因可以檢視 深入理解 Slice

驗證

package main

import (
	"fmt"
)

type carListType map[string]string

var carList = make(carListType)

func main() {
	age := 10
	fmt.Printf("addr is:%p\n"
,&age) //addr is:0xc000018088 sayAge(age) setAge(&age) fmt.Printf("after setAge,age is:%d\n",age) // after setAge,age is:30 carList["honda"] = "civic" carList["bmw"] = "320li" fmt.Printf("carList is:%v\n",carList) // carList is:map[bmw:320li honda:civic] fmt.Printf("carList value is:%p\n"
,carList) // carList value is:0xc000098000 fmt.Printf("carList addr is:%p\n",&carList) // carList addr is:0x1173648 setCar(carList) // setCar carList addr is:0xc00008e000 fmt.Printf("after setCar carList is:%v\n",carList) // after setCar carList is:map[bmw:520li honda:civic] } func sayAge(age int) { fmt.Printf("addr is:%p\n"
,&age) //addr is:0xc000018098 fmt.Printf("my age is:%d\n",age is:30 } func setAge(age *int) { *age = 30 fmt.Printf("age point value is:%p\n",age) //age point value is:0xc000018088 fmt.Printf("age point addr is:%p\n",&age) //age point addr is:0xc00008a020 } func setCar(carList carListType) { fmt.Printf("setCar carList value is:%p\n",carList) // setCar carList value is:0xc000094000 fmt.Printf("setCar carList addr is:%p\n",&carList) // setCar carList addr is:0xc00008e020 carList["bmw"] = "520li" } 複製程式碼

pointer 和 value 型別作為 receiver 有什麼區別?主要在於你是否需要修改receiver,有如下幾個注意事項:

  • 如果你需要修改receiver,那必須是pointer;
  • 因為 slice 和 map 是引用型別,因此這裡有點微妙,他們以value作為 receiver 是可以修改receiver 的,但是如果要修改自身熟悉,比如slice的長度,那還是需要以pointer作為receiver;
  • 如何receiver很大,例如一個很大的結構,那麼 pointer receiver效能會更佳。可以參考從記憶體分配策略(堆、棧)的角度分析,函式傳遞指標真的比傳值效率高嗎?
  • 官方建議如果型別的某些方法具有 pointer receiver,那麼其餘的方法也保持一致,使得方法集一致
  • 對於基礎型別、小型slice、map之類,除非強制要求,否則使用value receiver的將很高效和清晰
package main

import "fmt"

type man struct {
	name string
	age  int
}

type carList map[string]string

func main() {
	kangkang := man{"kangkang",10}

	fmt.Printf("name:%s,age:%d\n",kangkang.name,kangkang.age) 
    // name:kangkang,age:10

	kangkang.setName()
	kangkang.setAge()

	fmt.Printf("name:%s,kangkang.age) 
    // name:kitty,age:10

	myCar :=carList{"honda":"red","bmw":"white"}
	myCar.addCar("benz","blue")

	fmt.Printf("carList: %v\n",myCar) 
    // carList: map[benz:blue bmw:white honda:red]
    // 雖然是value receiver ,依然新增成功了,符合預期
}

// method on pointer
func (m *man) setName() {
	m.name = "kitty"
}

// method on value
func (m man) setAge() {
	m.age = 30
}

func(m carList) addCar(brand string,color string)  {
	m[brand]=color
}
複製程式碼