Go语言中函数的参数都是按值进行传递的,即使参数是指针,也是指针的一个副本。习惯上把指针的函数参数称之为地址传参,即引用传递,而非指针的函数参数称为值传参
地址传参在大对象上效率比值传参好,在内部相当于用指针地址赋值,而不用复制整个对象
一、数组的值传递
Golang数组作为参数传入函数时,进行的是值传递,这里与Java数组的引用传递是不同的,示例如下
package main
import "fmt"
func main() {
arr := [8]int{}
for i := 0; i < 8; i++ {
arr[i] = i
}
fmt.Println(arr)
exchange(arr)
fmt.Println(arr)
}
func exchange(arr [8]int) {
for k, v := range arr {
arr[k] = v * 2
}
}
运行结果如下:
二、数组的引用传递
需要注意的是,golang中本质上是没有引用传递的,这里只不过是通过值传递来传递指针,main函数的arr和exchangeByAddress的arr地址是不一致的,但是他们指针的值是相同的,也就是修改的同一块内存的数据,所以能实现引用传递的效果
默认情况下Golang的数组传递是值传递,但当我们想要对传入的数组进行修改时,可以使用指针来对数组进行操作,如下
package main
import "fmt"
func main() {
arr := [8]int{}
for i := 0; i < 8; i++ {
arr[i] = i
}
fmt.Println(arr)
exchangeByAddress(&arr)
fmt.Println(arr)
}
func exchangeByAddress(arr *[8]int) {
for k, v := range *arr {
arr[k] = v * 2
}
}
运行结果如下:
三、切片的引用传递(本质依旧是指针的值传递)
Golang中的切片与Java中的ArrayList集合类似,进行的是引用传递
严格来说golang没有引用传递,下面示例汇总虽然在exchangeSlice内对切片的修改反馈到了main函数中,但是内部和外部的slice的地址其实是不一样的。两个slice的地址不一致,但是他们指向了同一个底层数组,在exchangeSlice函数内的变更最后反馈到了底层数组上。
package main
import "fmt"
func main() {
slice := []int{1,2,3,4,5}
fmt.Println(slice)
exchangeSlice(slice)
fmt.Println(slice)
}
func exchangeSlice(slice []int) {
for k, v := range slice {
slice[k] = v * 2
}
}
运行结果:
这里需要格外注意,在内部exchangeSlice函数内如果发生了底层数组的扩容,那么exchangeSlice内的slice则会申请新的数组,在扩容后的slice做的变更也将不会再反馈到外部main函数的slice中
package main
import "fmt"
func main() {
slice := []int{1,2,3}
fmt.Println(slice)
exchangeSlice(slice)
fmt.Println(slice)
}
func exchangeSlice(slice []int) {
slice = append(slice, 4, 5, 6); // 原始数组大小为4,超过4会扩容
for k, v := range slice {
slice[k] = v * 2
}
fmt.Println(slice)
}
运行结果: