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]