Go的参数传递

2022/09/06

Go的参数传递

结论:Go的参数传递一定是值传递的。

参数传递指的是将变量传入到函数内。

先搞明白两个概念:

  • 变量名:一个标识符
  • 变量内容:变量指向的内容

对于变量,会区分基础类型和引用类型。基础类型的变量传入到函数内,是完全的复制过去,是值传递;引用类型的变量传入到函数内,也是完全的复制过去,但复制的是指针的地址,这也是值传递。下面一段代码可以解释:

package main

import "fmt"

func change(p1 []int) {
	fmt.Printf("p1的内存地址是: %p\n", &p1)        // p1的内存地址是: 0xc000010060
	fmt.Printf("函数里接收到slice的内存地址是:%p\n", p1) // 函数里接收到slice的内存地址是:0xc000100000

	p1 = append(p1, 30)
}

func main() {
	p := make([]int, 3) // 返回一个指针
	p = append(p, 20)
	fmt.Printf("p的内存地址是: %p\n", &p)   // p的内存地址是: 0xc000010030
	fmt.Printf("slice的内存地址是:%p\n", p) // slice的内存地址是:0xc000100000

	change(p)                            // 重新生成一份地址p1 指向slice地址
	fmt.Printf("修改之后p的内存地址 %p\n", &p)    // 修改之后p的内存地址 0xc000010030
	fmt.Printf("修改之后slice的内存地址 %p\n", p) // 修改之后slice的内存地址 0xc000100000
	fmt.Println("修改之后的slice:", p)        // 修改之后的slice [0 0 0 20]
	fmt.Println(*&p)                     // [0 0 0 20]
}

p的内存地址是: 0xc000010030
slice的内存地址是:0xc000100000
p1的内存地址是: 0xc000010060
函数里接收到slice的内存地址是:0xc000100000
修改之后p的内存地址 0xc000010030
修改之后slice的内存地址 0xc000100000
修改之后的slice: [0 0 0 20]
[0 0 0 20]

可以看到,引用类型的变量在传递过程中,其实是对指针进行了一个拷贝,且在函数内的变化不会影响到主函数的引用类型的变化。

这个实现细节必须要注意,尤其是对变量进行赋值的时候,如果值是引用类型,尽量使用copy()函数保证两者可以分离。

注意:slice、map、channel 通过 make 创建后,返回的都是指针。

上述的例子还揭示了 slice 的传递过程,请参考:2021-07-17-slice是完美的引用传递吗

Search

    Table of Contents