首先,slice
本身是个结构体,它内部第一个元素是一个指针类型,指向底层的具体数组。
当它作为参数传递进函数时,会对整个结构体做一个拷贝并产生一个新地址存放这个结构体。但结构体内部的数据并没有发生改变,也就是说拷贝产生的数据的指针类型指向同一个数组。
当这时在函数内部操作修改该slice
时,会影响函数外部的slice
:
package main
import "fmt"
func main() {
slice := make([]int, 0)
slice = append(slice, 1, 2, 3)
modify(slice)
fmt.Println(slice)
}
func modify(arr []int) {
arr[0] = 11
}
输出结果:
$go run main.go
[11, 2, 3]
因为slice
是引用类型,指向的是同一个数组。在函数内外,arr
本身的地址变了,但是两个指针指向的数组地址是不变的。所以在函数内部的修改可以影响到函数外部。
但如果在函数内使用append
增加数据时,情况就复杂多了,分两种情况:
当slice没有足够的容量(capacity)
```go package main
import "fmt"
func main() { arr := make([]int, 0) arr = append(arr, 1, 2, 3) fmt.Println(arr) }
func appendSlice(arr []int) { arr = append(arr, 4) } ```
输出结果:
$ go run main.go
[1, 2, 3]
当slice有足够的容量(capacity)
```go package main
import "fmt"
func main() { arr := make([]int, 0, 5) arr = append(arr, 1, 2, 3) fmt.Println(arr) }
func appendSlice(arr []int) { arr = append(arr, 4) } ```
输出结果:
$ go run main.go
[1, 2, 3]
虽然看似输出结果都一样,函数内部进行append
后没有造成外部的数据新增。但是原理却是不一样的。
当容量足够的时候
* 在内部调用append
的时候,由于cap容量
足够,所以不需要扩容,所以函数内操作的数组和函数外的一致
。但因为函数外的len
是增加之前的数,所以函数外只会遍历到增加之前的位置就停下,但实际上这个数组的长度已经变更。
内存分布如下图:
当容量不足的时候
* 在内部调用append
的时候,由于cap容量
不足,需要进行扩容,这时函数内操作的数组就是一块新的。所以函数内的操作不会影响函数外的数组。
内存分布如下图:
在函数内修改slice并在外部生效的正确姿势应该是传入指针:
package main
func appendElement(arr *[]int){
*arr = append(*arr, 1)
}
传指针进去,这样拷贝的就是这个指针,指针指向的对象,也就是slice本身,是不变的,使用*arr可以对slice进行操作。
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建