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]