概要

今天改了一段代码,调用函数时把一个 sync.Map 类型的变量作为传参,在函数内部修改 sync.Map 变量的值,发现函数处理完成后,外部的变量没有修改,后来发现 sync.Map 是一个普通的结构体,跟所有的结构体一样,golang 在把结构体类型作为函数传参时,都是值传递,即创建参数的一个副本,然后传递给函数。这也就意味着,如果你在函数内部修改了这个副本的值,那么原始的值是不会被影响的。

验证过程

函数参数类型为 *sync.Map

从运行结果来看,函数内部的修改影响了原始变量。

func main() {
	var result sync.Map
	result.Store(10, 11)
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true  // 返回 false 则表示停止迭代
	})
	fmt.Println("---------------------------")
	GetTaskCountValueMap(&result) // 传的是指针类型
	fmt.Println("---------------------------")
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true
	})
}

func GetTaskCountValueMap(result *sync.Map) {
	for i := 0; i < 3; i++ {
		result.Store(i, i+1)
	}
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true
	})
}

输出结果

key=10 val=11
---------------------------
key=0 val=1
key=1 val=2
key=2 val=3
key=10 val=11
---------------------------
key=10 val=11
key=0 val=1
key=1 val=2
key=2 val=3

函数传参类型为 sync.Map

从运行结果来看,函数内部的修改不会影响原始变量。

func main() {
	var result sync.Map
	result.Store(10, 11)
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true  // 返回 false 则表示停止迭代
	})
	fmt.Println("---------------------------")
	GetTaskCountValueMap(result) // 传的是普通结构体类型
	fmt.Println("---------------------------")
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true
	})
}

func GetTaskCountValueMap(result sync.Map) {
	for i := 0; i < 3; i++ {
		result.Store(i, i+1)
	}
	result.Range(func(key, value any) bool {
		fmt.Printf("key=%v val=%v\n", key, value)
		return true
	})
}

输出结果

key=10 val=11
---------------------------
key=10 val=11
key=0 val=1
key=1 val=2
key=2 val=3
---------------------------
key=10 val=11

golang 函数传参提醒

结构体、数组和基本数据类型都是值传递

在Go语言中,无论是结构体还是基本数据类型,当他们作为函数参数传递时,都是值传递。如果在函数内部修改了副本的值,原始的值是不会被影响。

切片、map 是引用传递

切片看起来是被作为值传递,但实际上切片(slice)的数据结构包含了指向底层数组的指针。这就意味着,当你将切片传递给函数时,虽然它是传的值(也就是切片自身的数据结构被复制),但是复制的切片和原始的切片依然共享同一个底层数组。因此,如果你在函数中修改了复制的切片中的元素,原始切片相对应的元素也会被修改。

跟切片类似,map 传递的也是对底层数据结构的引用