深刻理解 Golang 指針

Go中一切都經過值傳遞,也就是說,一個函數老是獲得值傳遞的副本,老是會分配一個值的副本給函數參數。例如git

  • 將int值傳遞的是int值的副本;
  • 指針傳遞指針的副本,而不是指針指向的數據;
  • map 和 slice 值相似於指針,他們是指向底層存儲數據結構的指針,複製map、slice的值,便不會複製他們指向的數據。具體緣由能夠查看 深刻理解 Slice

驗證github

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) // after setAge, 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,有以下幾個注意事項:golang

  • 若是你須要修改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, age:%d\n", kangkang.name, 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
}
複製代碼
相關文章
相關標籤/搜索