函数参数传递的本质
值传递
值传递: 将变量的一个副本传递给函数,函数中不管如何操作该变量副本,都不会改变原变量的值。
引用传递
引用传递:将变量的内存地址传递给函数,函数中操作变量时会找到保存在该地址的变量,对其进行操作,会改变原变量的值
Go语言参数的传递形式总是值传递
值类型变量
对于int、string和bool等值类型变量,传递的是原变量的副本,对副本的操作不会影响原变量。
举例:
package main
import "fmt"
func passByValue(numPara int) {
fmt.Println("passByValue函数中变量numPara地址为: ", &numPara) // &参数= 参数的地址
numPara = 100
fmt.Println("对值变量在自定义的函数内部进行修改后为 : ", numPara)
}
func main() {
num := 1
fmt.Println("main函数中的num地址为: ", &num)
passByValue(num)
fmt.Println("main函数中的num变量的值: ", num)
}
// main函数中的num地址为: 0xc000014098
// passByValue函数中变量numPara地址为: 0xc0000140c0
// 对值变量在自定义的函数内部进行修改后为 : 100
// main函数中的num变量的值: 1
结论:
-
main函数中定义的 num 地址 ,和 自定义函数中的 参数num 地址不一样,说明自定义函数中的num为main函数num的副本
-
对自定义函数num的修改,即为在函数内部对局部变量进行修改,无法影响mian函数的num 。因此局部参量(副本) 的改变无法影响主变量的参数(main函数中的num)
引用类型变量
对于指针、切片、map和channel(通道)引用类型变量,传递的是原变量指针的一份副本,该副本指向了原变量地址,因此对该副本的操作会影响原变量,从而达到了其他编程语言中类似于引用传递的效果。
举例1:
package main
import "fmt"
func passByReference(numPara *int) {
fmt.Println("passByReference函数中指针变量numPara(引用型变量)内容为: ", numPara)
fmt.Println("passByReference函数中指针变量numPara(引用型变量)地址为: ", &numPara)
fmt.Println("对指针变量进行修改 ..... ")
*numPara = 100
fmt.Println("对指针变量(引用型变量)在自定义的函数内部进行修改后内容为 : ", numPara)
fmt.Println("对指针变量(引用型变量)在自定义的函数内部进行修改后地址为 : ", &numPara)
}
func main() {
num := 1
fmt.Println("main函数中的num地址为: ", &num)
passByReference(&num)
fmt.Println("main函数中的num变量的值: ", &num)
}
// main函数中的num地址为: 0xc0000aa058
// passByReference函数中指针变量numPara(引用型变量)内容为: 0xc0000aa058
// passByReference函数中指针变量numPara(引用型变量)地址为: 0xc0000ce020
// 对指针变量进行修改 .....
// 对指针变量(引用型变量)在自定义的函数内部进行修改后内容为 : 0xc0000aa058
// 对指针变量(引用型变量)在自定义的函数内部进行修改后地址为 : 0xc0000ce020
// main函数中的num变量的值: 0xc0000aa058
可以看出:
- 在自定义函数中对引用型变量(也就是是指针)进行修改会影响到main() 函数中定义的引用型变量(此处为指针)
举例2 :
使用map变量传递的是原变量的指针。
package main
import "fmt"
func passByReference(mapNumReference map[int]int) {
fmt.Println("passByReference函数中变量mapNumReference地址为: ", mapNumReference)
fmt.Println("passByReference函数中变量mapNumReference所属指针地址为: ", &mapNumReference)
mapNumReference[1] = 100
}
func main() {
mapNum := map[int]int{1: 10}
fmt.Println("main函数中的变量mapNum为: ", mapNum)
fmt.Println("main函数中的变量mapNum所属的指针地址为: ", &mapNum)
fmt.Println("mapNum变量值为: ", mapNum)
passByReference(mapNum)
fmt.Println("main函数中的变量mapNum为: ", mapNum)
}
// main函数中的变量mapNum为: map[1:10]
// main函数中的变量mapNum所属的指针地址为: &map[1:10]
// mapNum变量值为: map[1:10]
// passByReference函数中变量mapNumReference地址为: map[1:10]
// passByReference函数中变量mapNumReference所属指针地址为: &map[1:10]
// main函数中的变量mapNum为: map[1:100]
通过map类型变量参数传递的例子我们可以发现,函数进行值传递后拷贝的是map类型变量指针,但拷贝后的指针地址指向的还是map的地址,从而导致在函数passByReference中对map的操作会影响原变量。