原理
Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。
一个例子
func change(a []int) {
fmt.Printf("v=%v,p=%p\n", a, &a)
a = append(a, 3)
fmt.Printf("v=%v,p=%p\n", a, &a)
a = append(a, 4)
a[0] = 11
a[1] = 22
fmt.Printf("v=%v,p=%p\n", a, &a)
}
func test5() {
a1 := make([]int, 2, 3)
a1[0] = 1
a1[1] = 2
fmt.Printf("v=%v,p=%p\n", a1, &a1)
change(a1)
fmt.Printf("v=%v,p=%p\n", a1, &a1)
}
输出
说明
1,a和a1是两个slice 只不过slice中指针指向是一样的,a在追加时超过了cap,重新分配内存,a中的数据指针指向变化,但是并没有影响a1,只是在函数内a发生赋值而已,与函数外的a没有任何关系,若想改变a1,最好采用传递a1的指针。
2,append一定是从长度开始追加的。
3,函数传递的本质是值传递。
4,slice是一个包含len cap ptr的结构
5,无论数组还是切片,都有长度限制。也就是追加切片的时候,如果元素正好在切片的容量范围内,直接在尾部追加一个元素即可。如果超出了最大容量,再追加元素就需要针对底层的数组进行复制和扩容操作了。
网友评论