1、案例一:

func main() {
//假如num为数组,结果又不一样,这个问题
//num := [7]int{1, 2, 3, 4, 5, 0, 6}
num := []int{1, 2, 3, 4, 5, 0, 6}
fmt.Printf("切片的内存地址%p", num)
fmt.Println()
fmt.Printf("切片的内存地址&%p", &num[0])
fmt.Println()
PassParameters(num)
}
func PassParameters(arg []int) {
fmt.Printf("切片作为形参传递后的内存地址%p", arg)
fmt.Println()
fmt.Printf("切片作为形参传递后的内存地址%p", &arg)
}

运行结果为:

go关于切片(slice)传参是值传递还是引用传递_赋值

F:\goweb\mytest> go run main.go

切片的内存地址0xc000010280

切片的内存地址&0xc000010280

切片作为形参传递后的内存地址0xc000010280

切片作为形参传递后的内存地址0xc000008090

从上面案例,我们发现几个问题:

第一:fmt.Printf("切片的内存地址%p", num)与fmt.Printf("切片的内存地址&%p", &num[0])   结果相同,说明一个问题。num默认地址是切片(数组的一部分)第一个单元。重温“切片”的定义:切片 (slice) 是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型。从这里可以得到一个结论:num切片是一个地址值,是指向引用数组的第一单元的地址(数组下标为0的索引)。这样就可以理解num地址与&num[0]地址相同了.

第二问题:下面这两个输出会一样吗?

fmt.Printf("切片的内存地址%p", num)

fmt.Printf("切片的内存地址%p", &num)

运行结果如下:两个结果不同,num本身 就是一个指针,也就是一个内存地址,再对num取&,就是获取指针变量的地址。不知道我说清楚了没有?

go关于切片(slice)传参是值传递还是引用传递_传参_02

第三问题:形参arg与实参num的指向都是同一个地址。从这里我们可以判断出来,形参与实参共同引用一个数组内存。那么现在问题来了,假如我们改变形参的值,实参会改变吗?

测试结果如下:形参改变值了,形参地址也改变了。实参并未受到影响。

package main
import (
"fmt"
"strconv"
"unsafe"
)
func main() {
//0代表节点为空
num := []int{1, 2, 3, 4, 5, 0, 6}
//num := 1
fmt.Printf("切片的内存地址%p", num)
fmt.Println()
fmt.Printf("切片第一单元的内存地址%p", unsafe.Pointer(&num[0]))
fmt.Println()
PassParameters(num)
fmt.Println(num)
}
func PassParameters(arg []int) {
fmt.Printf("未对形参切片赋值前的内存地址%p", arg)
fmt.Println()
arg = append(arg, 7)
fmt.Printf("赋值后形参切片的内存地址%p", arg)
fmt.Println()
fmt.Println(arg)

}

go关于切片(slice)传参是值传递还是引用传递_内存地址_03

第四个问题:假如我们不对形参进行追加新单元值,只修改形参的单元值,实参是否改变?

测试:

go关于切片(slice)传参是值传递还是引用传递_golang_04

输出结果:形参与实参的引用地址都没有改变。结果就是形参修改的新值会影响到实参的结果。

go关于切片(slice)传参是值传递还是引用传递_赋值_05


结论:切片在形参传递过程中。形参与实参共同引用一个底层数组,只要底层数组长度未改变,形参与实参就是达到引用传递,假如形参切片在被追加单元值导致底层数组必须重建,那么形参的修改就不会影响到实参。这个时候就是值的传递