go語言基礎值傳遞

 閱讀大約需要1分鐘

go語言基礎值傳遞

go語言中只有值傳遞,沒有引用傳遞

值傳遞是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數,函數外和函數里對這個參數地址求值應該是不一樣的。

引用傳遞是指在調用函數時將實際參數的地址直接傳遞到函數中,那麼在函數中對參數所進行的修改,將影響到實際參數。

值傳遞和引用傳遞的區別並不是傳遞的內容,而是實參到底有沒有被複製一份給形參。 在判斷實參內容有沒有受影響的時候,要看傳的是什麼,如果你傳遞的是個地址,那麼就看這個地址的變化會不會有影響,而不是看地址指向的對象的變化。

package main

import "fmt"

func main() {
	slice := []int{0,1,2,3}
	m := make(map[string]string)
	m["A"] = "a"
	var i *int
	a := 123
	i = &a
	fmt.Printf("[main pointer] %p\n", &i)
	fmt.Printf("[main map] %p\n", &m)
	fmt.Printf("[main slice] %p\n", &slice)
	get(slice, m, i)
	fmt.Println(slice)
	fmt.Println(m)
	fmt.Println(*i)
}

func get(s []int, m map[string]string, i *int)  {
	fmt.Printf("[get pointer] %p\n", &i)
	fmt.Printf("[get map] %p\n", &m)
	fmt.Printf("[get slice] %p\n", &s)

	s[1] = 9
	m["A"] = "Hello"
	a := 456
	i = &a
}

運行結果如下:

[main pointer] 0xc00000e030
[main map] 0xc00000e028
[main slice] 0xc00000c030
[get pointer] 0xc00000e048
[get map] 0xc00000e040
[get slice] 0xc00000c048
[0 9 2 3]
map[A:Hello]
123

可以發現slice、map、指針在傳遞過程中地址都發生了變化,這說明傳遞的是一份拷貝。

但是我們又發現在函數里修改slice、map,函數外的值也會改變,這是為什麼呢?

slice本身是個結構體,源碼裡的定義如下:

type slice struct {
    array unsafe.Pointer
    len int
    cap int
}

slice底層是通過指針指向數組的,故函數內的切片跟函數外的切片訪問的數組是同一個地址的,函數內修改切片也會影響到函數外的切片。

package main

import (
	"fmt"
	"log"
)

var str []string

func main()  {
	fmt.Printf("[main slice] %p\n", str)
	fmt.Printf("[main slice] %p\n", &str)
	str=[]string{"c"}
	fmt.Printf("[main slice c] %p\n", str)
	fmt.Printf("[main slice c] %p\n", &str)
	setVal(&str)

	log.Println(str)
}

func setVal(val *[]string)  {
	fmt.Printf("[val slice] %p\n", &val)
	*val = []string{"a", "b"}
	fmt.Printf("[val slice] %p\n", val)
}

運行結果如下:

[main slice] 0x0
[main slice] 0x113e0b0
[main slice c] 0xc000010230
[main slice c] 0x113e0b0
[val slice] 0xc00000e030
[val slice] 0x113e0b0
[a b]