回顾下slice的结构,gopl中写到,一个slice由三个部分构成:指针、长度和容量。当把一个slice作为函数参数进行传递时,实际上是把该指针进行传递。
在被调用函数(Callee)中的slice是该指针的一个副本,在被调用函数中对副本进行任何的修改都不会影响到调用者函数(Caller)中的slice结构(Callee中append的元素将不会被Caller访问到)
package main
import (
"fmt"
)
func main() {
stack := make([]string, 0, 5)
stack = append(stack, "astring")
fmt.Printf("len: %v, cap: %v \n", len(stack), cap(stack))
outline(stack)
fmt.Printf("val: %v, addr: %p\n", stack, stack)
// fmt.Printf("len: %v, cap: %v \n", len(stack), cap(stack))
// 输出结果为 len: 1, cap: 5
// 说明Callee中的append并不影响Caller中的slice
}
func outline(stack []string) {
stack = append(stack, "bstring")
fmt.Printf("val: %v, addr: %p\n", stack, stack)
}
len: 1, cap: 5
val: [astring bstring], addr: 0xc00006c050
val: [astring], addr: 0xc00006c050
如果修改初始化stack时的capacity为0或1,则发现Caller和Callee中的stack指针地址不同,因为在Callee中进行了数组扩容,切片指向的底层数组已经有所不同。
len: 1, cap: 1
val: [astring bstring], addr: 0xc000124000
val: [astring], addr: 0xc00010a210
Program exited.