Contents

GO参数传递

参数传递

  Go在传递参数时是传值还是传引用,不同的选择会影响我们在函数中修改入参时是否会影响调用方看到的数据。

::: tip 传值和传引用两者的区别

  • 传值:函数调用时会对参数进行拷贝,被调用方和调用方两者持有不相关的两份数据;
  • 传引用:函数调用时会传递参数的指针,被调用方和调用方两者持有相同的数据,任意一方做出的修改都会影响另一方; :::

  不同语言会选择不同的方式传递参数,Go 选择了传值的方式,无论是传递基本类型、结构体还是指针,都会对传递的参数进行拷贝

整型和数组

  函数 myFunction 接收了两个参数,整型变量 i 和数组 arr,这个函数会将传入的两个参数的地址打印出来,在最外层的主函数也会在 myFunction 函数调用前后分别打印两个参数的地址:

func myFunction(i int, arr [2]int) {
	fmt.Printf("in my_funciton - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
}

func main() {
	i := 30
	arr := [2]int{66, 77}
	fmt.Printf("before calling - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
	myFunction(i, arr)
	fmt.Printf("after  calling - i=(%d, %p) arr=(%v, %p)\n", i, &i, arr, &arr)
}

$ go run main.go
before calling - i=(30, 0xc00009a000) arr=([66 77], 0xc00009a010)
in my_funciton - i=(30, 0xc00009a008) arr=([66 77], 0xc00009a020)
after  calling - i=(30, 0xc00009a000) arr=([66 77], 0xc00009a010)

main 函数和被调用者 myFunction 中参数的地址完全不同。

main 函数的角度来看,在调用 myFunction 前后,整数 i 和数组 arr 两个参数的地址都没有变化。

如果在 myFunction 函数内部对参数进行修改, 也仅仅影响了当前函数, 并没有影响调用方 main 函数。

::: tip 结论 Go 语言的整型和数组类型都是值传递的,也就是在调用函数时会对内容进行拷贝。 :::

::: warning 需要注意的是如果当前数组的大小非常的大,这种传值的方式会对性能造成比较大的影响。 :::

结构体和指针

  定义了一个结构体 MyStruct 以及接受两个参数的 myFunction 方法:

type MyStruct struct {
	i int
}

func myFunction(a MyStruct, b *MyStruct) {
	a.i = 31
	b.i = 41
	fmt.Printf("in my_function - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
}

func main() {
	a := MyStruct{i: 30}
	b := &MyStruct{i: 40}
	fmt.Printf("before calling - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
	myFunction(a, b)
	fmt.Printf("after calling  - a=(%d, %p) b=(%v, %p)\n", a, &a, b, &b)
}

$ go run main.go
before calling - a=({30}, 0xc000018178) b=(&{40}, 0xc00000c028)
in my_function - a=({31}, 0xc000018198) b=(&{41}, 0xc00000c038)
after calling  - a=({30}, 0xc000018178) b=(&{41}, 0xc00000c028)

::: tip 结论

  • 传递结构体时:会拷贝结构体中的全部内容;
  • 传递结构体指针时:会拷贝结构体指针; :::

  修改结构体指针是改变了指针指向的结构体,b.i 可以被理解成 (*b).i,也就是我们先获取指针 b 背后的结构体,再修改结构体的成员变量。

传值

  Go 语言在传递参数时使用了传值的方式,接收方收到参数时会对这些参数进行复制;在传递数组或者内存占用非常大的结构体时,尽量使用指针作为参数类型来避免发生数据拷贝进而影响性能。