array & slice #
Slice append #
对 slice(切片)操作append时要小心。
- 当 cap 容量还没有变化时,slice 是对数据本身的引用,append 会修改被引用的值
- 当 slice 操作 append 使 cap 容量变化后,slice 会复制被引用的数组切断之前和数组的关系。
func main() {
var array =[]int{1,2,3,4,5}// len:5,capacity:5
var newArray=array[1:3]// len:2,capacity:4 (已经使用了两个位置,所以还空两位置可以append)
fmt.Printf("%p\n",array)
fmt.Printf("%p\n",newArray) // 可以看到newArray的地址指向的是array[1]的地址,即他们底层使用的还是一个数组
fmt.Printf("%v\n",array) //[1 2 3 4 5]
fmt.Printf("%v\n",newArray) //[2 3]
newArray[1]=9 //更改后array、newArray都改变了
fmt.Printf("%v\n",array) // [1 2 9 4 5]
fmt.Printf("%v\n",newArray) // [2 9]
newArray=append(newArray,11,12)//append 操作之后,array的len和capacity不变,newArray的len变为4,capacity:4。因为这是对newArray的操作
fmt.Printf("%v\n",array) //[1 2 9 11 12] //注意对newArray做append操作之后,array[3],array[4]的值也发生了改变
fmt.Printf("%v\n",newArray) //[2 9 11 12]
newArray=append(newArray,13,14) // 因为newArray的len已经等于capacity,所以再次append就会超过capacity值,
// 此时,append函数内部会创建一个新的底层数组(是一个扩容过的数组),并将array指向的底层数组拷贝过去,然后在追加新的值。
fmt.Printf("%p\n",array)
fmt.Printf("%p\n",newArray)
array[1] = 10
newArray[1] = 13
fmt.Printf("%v\n",array) //[1 10 9 11 12]
fmt.Printf("%v\n",newArray) //[2 13 11 12 13 14] 他两已经不再是指向同一个底层数组 array了
}
数组是 go 中的值类型,而 slice 是引用类型。
Array copy #
package main
import "fmt"
func main() {
sample1 := [2]string{"a", "b"}
fmt.Printf("Sample1 Before: %v\n", sample1)
sample2 := sample1
sample2[1] = "c"
fmt.Printf("Sample1 After assignment: %v\n", sample1)
fmt.Printf("Sample2: %v\n", sample2)
test(sample1)
fmt.Printf("Sample1 After Test Function Call: %v\n", sample1)
}
func test(sample [2]string) {
sample[0] = "d"
fmt.Printf("Sample in Test function: %v\n", sample)
}
output:
Sample1 Before: [a b]
Sample1 After assignment: [a b]
Sample2: [a c]
Sample in Test function: [d b]
Sample1 After Test Function Call: [a b]
Slice copy #
使用 copy 函数进行拷贝:
func copy(dst, src []Type) int
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 5)
numberOfElementsCopied := copy(dst, src)
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//After changing numbers2
dst[0] = 10
fmt.Println("\nAfter changing dst")
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
}
output:
Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]
After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]
Slice internals #
Slice 结构:
A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).