golang slice参数传递

在介绍slice函数参数传递之前,先介绍一下slice的结构

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

这个应该周知了,也不必多解释,需要注意两个问题

1、如何初始化slice

我们知道初始化slice有几种方式,注意以下代码,参考链接

var foo []int         // 1
foo := []int{}		  // 2
foo := make([]int, 0) // 3

那么这些方式有什么区别吗?

简单来说,1中foo == nil,2和3中foo != nil,并且2和3初始化了底层的array指针的地址,并且len == 0, capacity == 0,2和3可以视为相同的。

2、如何打印slice的地址

注意以下代码

slice := []int{1}
fmt.Printf("%p", slice)     // 1
fmt.Printf("%p", &slice)    // 2
fmt.Printf("%p", &slice[0]) // 3

主要其实fmt.Printf(“%p”)对slice处理是有优化的,参考fmt
golang slice参数传递_第1张图片
那么其实1和3结果是相同的。都是打印slice[0]的地址。但是2的结果有所不同,因为&slice其实是slice变量的地址,而不是其中array的地址。

搞清楚上面两个问题后,我们再来看将slice作为参数传递给函数,看如下代码,参考链接

package main

import "fmt"

func main() {
	slice := []int{}
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
	test(slice)
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
}

func test(slice []int) {
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
	slice = append(slice, 1)
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
}

输出:

0x55d008, 0xc000010030, []
0x55d008, 0xc000010078, []
0xc00001c038, 0xc000010078, [1]
0x55d008, 0xc000010030, []

可以看出有几点符合预期的。

  1. slice和&slice的地址,在main函数中不变且不同
  2. slice在test中append前地址不变

但是有几点不符合预期:

  1. slice的内容在进入test后并没有变化
  2. &slice的值在进入test后发生了变化
  3. slice的地址在append后发生了变化

为什么会这样呢?其实本质是这样的

  1. golang的函数调用都是值传递,而传入的slice除了array是地址,len和capacity都是值

这样就可以解释了,由于值传递,所以有第4点,slice已经发生了copy;但由于array是地址,所以有第2点;但是由于len和capacity是值传递,所以都是0, 那么append操作会新申请内存并返回,所以有第5点,slice的地址发生了变化;并且由于main函数中len还是0,所以导致第3点,内容没有发生变化。

如果将capacity改大,如下代码,会有不同的输出

package main

import "fmt"

func main() {
	slice := make([]int, 0, 10)
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
	test(slice)
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
}

func test(slice []int) {
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
	slice = append(slice, 1)
	fmt.Printf("%p, %p, %v\n", slice, &slice, slice)
}

输出

0xc0000b2000, 0xc0000a8018, []
0xc0000b2000, 0xc0000a8060, []
0xc0000b2000, 0xc0000a8060, [1]
0xc0000b2000, 0xc0000a8018, []

结合之前内容,不难解释原因了吧。

你可能感兴趣的:(golang,开发语言,后端)