slice行为
slice的结构
- 指向数组的指针
- 长度
- 容量
作为函数参数传递时:
Golang函数参数传递基本上是按值传递的,slice也与之相同,因此传递变量的指针是不同的。
func main(){
s:= [] int { 1,2,3 }
fmt.Printf("%p\n", &s) // 0x1040a0b0
someFunc(s)
}
func someFunc(s [] int){
fmt.Printf("%p\n", &s) //与0x1040a0c0不同
}
为什么可以通过slice仍然可以访问相同的元素?原因是由值传递的slice所保持的数组的指针是相同的。
func main(){
s:= [] int { 1,2,3 }
fmt.Printf("%p\n", &s) // 0x1040a0b0
fmt.Printf("%p\n", &s[0]) // 0x10410020
someFunc(s)
}
func someFunc(s [] int){
fmt.Printf("%p\n", &s) // 0x1040a0c0
fmt.Printf("%p\n", &s[0]) //与0x10410020相同
}
append:
- 对于容量不足时,append会导致数组重定位
func main(){
s:= [] int { 1,2,3 }
fmt.Printf("%P\n", &s) // 0X1040a0b0
fmt.Printf("%P\n", &s[0]) // 0x10410020
s = append(s, 4)
fmt.Printf("%p\n", &s) // 0x1040a0b0
fmt.Printf("%p\n", &s[0]) // 0x10454000指向新数组
}
当由函数参数传递时
如果append到函数内部,它将与调用者Slice看到的array不同。因此,函数内的array增加,但调用者的Slice不会改变。
func main() {
s := []int{1, 2, 3}
fmt.Printf("%p\n", &s[0]) // 0x10410020
add(s)
fmt.Println(s) // [1 2 3]
fmt.Printf("%p\n", &s[0]) // 0x10410020
}
func add(s []int) {
fmt.Printf("before: %p\n", &s[0]) // 0x10410020
s = append(s, 4)
fmt.Println(s) // [1 2 3 4]
fmt.Printf("after: %p\n", &s[0]) // 指针变为0x10454020
}
- 当容量足够时
当有足够的容量时,Slice不会重新排列,所以内容永远不会改变。
func main() {
s := make([]int, 3, 4)
s[0], s[1], s[2] = 1, 2, 3
fmt.Printf("%p\n", &s) // 0x1040a0b0
fmt.Printf("%p\n", &s[0]) // 0x10410020
s = append(s, 4)
fmt.Printf("%p\n", &s) // 0x1040a0b0
fmt.Printf("%p\n", &s[0]) // 0x10410020指向同一个数组
}
当由函数参数传递时
func main() {
s := make([]int, 3, 4)
s[0], s[1], s[2] = 1, 2, 3
fmt.Printf("%p\n", &s[0]) // 0x10410020
add(s)
fmt.Println(s) // [1 2 3]
fmt.Printf("%p\n", &s[0]) // 0X10410020指代相同的地址
}
func add(s []int) {
fmt.Printf("before: %p\n", &s[0]) // 0x10410020
s = append(s, 4)
fmt.Println(s) // [1 2 3 4]
fmt.Printf("after: %p\n", &s[0]) // 0x10410020指向同一个数组
即使它们指向相同的地址,打印值也不同。这是因为调用者的Slice长度尚未更新。add()
在函数中,它append
也4
变为len ,但由于调用者的是一个单独的对象,因此3
它保持不变。
在这种情况下,如果还想更新调用者
func main() {
s := make([]int, 3, 4)
s[0], s[1], s[2] = 1, 2, 3
fmt.Printf("%p\n", &s[0])
add(s)
s = s[:cap(s)] // 追加
fmt.Println(s) // [1 2 3 4]
fmt.Printf("%p\n", &s[0])
}
Slice行为:
- slice有一个指向数组的指针
- 通过参数传递的slice是通过值传递的,所以它是不同的。但指针内部指向的数组是相同的
- append时array指向发生重定位等变化
发表评论
要发表评论,您必须先登录。