Go 参数传递
Go 的参数传递和 Java 一样都是值传递,下面我会用slice编写五个例子详细说明各种参数传递情况
直接传递slice
func foo(a []int) {
a[0] = 200
}
func TestSlice(t *testing.T) {
a := []int{1, 2}
foo(a)
fmt.Println(a)
}
上面的执行结果是:
[200,2]
很简单,也符合我们的直觉,因为slice是引用类型嘛。
slice赋值
func foo(a []int) {
a = []int{100, 200}
}
func TestSlice(t *testing.T) {
a := []int{1, 2}
foo(a)
fmt.Println(a)
}
因为a是值传递,使用a的值修改了,没有影响
slice扩容
func foo(a []int) {
a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
a[0] = 200
}
func TestSlice(t *testing.T) {
a := []int{1, 2}
foo(a)
fmt.Println(a)
}
上面的执行结果是:
[1,2]
这个的原因是 在 foo 函数中,切片 a 传入并发生了 append 操作。由于 a 的容量不够容纳新增的元素,append 会创建一个新的底层数组,并返回一个新的切片 a。因此,在 foo 函数中的 a 变量现在指向的是新的底层数组,而不再指向原来的底层数组。
修改Slice
func foo(a []int) {
a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
a[0] = 200
}
func TestSlice(t *testing.T) {
a := make([]int, 2, 10)
a[0] = 100
a[1] = 99
foo(a)
fmt.Println(a)
}
//[200 99]
在这个测试中a的容量足够,所以在append的时候不需要创建新的底层数组,所以a[0]被成功修改。
但是a经过foo函数后len还是2,只能打印两个元素。这是因为参数传递是值传递
简单的说传递的是 slice的定义的值
slice的定义有三个值
- len
- cap
- 数组指针
在foo中修改切片中的值,修改的是数组指针的值,所以两边都可见。但是修改不了len和cap,因为他们是基本类型值传递。下面我证明在foo中修改了数组指针中的值
证明修改了切片中的值
func foo(a []int) {
fmt.Println(len(a), cap(a))
a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
fmt.Println(len(a), cap(a))
a[0] = 200
}
func TestSlice(t *testing.T) {
a := make([]int, 2, 10)
a[0] = 100
a[1] = 99
foo(a)
//2,10,1,2,3,4,5,6,7,8
fmt.Println(len(a), cap(a))
index := 5
fmt.Println("Value at index", index, "is", getSliceNum(a, index))
fmt.Println(a)
}
func getSliceNum(a []int, index int) interface{} {
if index >= cap(a) {
fmt.Println("Index is out of range for the slice's cap.")
return nil
}
// 获取切片的指针
ptr := unsafe.Pointer(&a[0])
// 计算目标索引的指针
targetPtr := unsafe.Pointer(uintptr(ptr) + uintptr(index)*unsafe.Sizeof(a[0]))
// 将指针转换回int类型
value := *(*int)(targetPtr)
return value
}
使用unsafe 直接访问地址,发现a[5]等于4,说明foo函数确实修改了其他值
修改len cap
上面我说因为值传递,无法修改cap和len,那么就没有办法了吗?方法是slice的引用(有点像指针的指针)
func foo(a *[]int) {
*a = append(*a, 1, 2, 3, 4, 5, 6, 7, 8)
(*a)[0] = 200
}
func TestSlice(t *testing.T) {
a := make([]int, 2, 10)
a[0] = 100
a[1] = 99
foo(&a)
fmt.Println(a)
}
输出如下
[200 99 1 2 3 4 5 6 7 8]