我试图在函数内的切片中添加一个元素。我可以更改切片的元素,但不能向其中添加新元素。既然切片就像参考,为什么我不能改变它?
下面是我试过的代码:
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3}
change(a)
fmt.Println(a)
}
func change(a []int) {
a[0] = 4
a = append(a, 5)
}
Run Code Online (Sandbox Code Playgroud)
切片是指向底层数组的指针。在 Golang 中是这样描述的:
映射和切片值的行为类似于指针:它们是包含指向底层映射或切片数据的指针的描述符。复制地图或切片值不会复制它指向的数据。复制接口值会复制存储在接口值中的事物。如果接口值包含一个结构体,则复制接口值会生成该结构体的副本。如果接口值持有指针,则复制接口值会复制指针,但不会复制它指向的数据。
您正在传递切片的副本而不是原始切片。附加到切片后返回值,然后将其分配给原始切片
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3}
a = change(a)
fmt.Println(a)
}
func change(a []int) []int{
a = append(a, 5)
return a
}
Run Code Online (Sandbox Code Playgroud)
或者您可以传递一个指向 int 切片的指针,但不建议这样做,因为切片本身是一个指向引导程序数组的指针。
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3}
change(&a)
fmt.Println(a)
}
func change(a *[]int){
*a = append(*a, 5)
}
Run Code Online (Sandbox Code Playgroud)
注意:Golang 中的一切都是按值传递的。
需要考虑的一件事是,即使您返回更新后的切片并分配相同的值,其原始 len 和 cap 也会发生变化,这将导致不同 len 的新底层数组。尝试打印更改切片前后的长度和上限以查看差异。
fmt.Println(len(a), cap(a))
Run Code Online (Sandbox Code Playgroud)
长度是切片引用的元素数。容量是底层数组中元素的数量(从切片指针引用的元素开始)。
由于底层数组将进行检查,您可以使用反射和不安全来检查它以获取底层数组,如果在附加数据后切片的上限发生变化,这是您的情况。
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
a := []int{1, 2, 3}
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&a))
data := *(*[3]int)(unsafe.Pointer(hdr.Data))
fmt.Println(data)
a = change(a)
hdr = (*reflect.SliceHeader)(unsafe.Pointer(&a))
newData := *(*[4]int)(unsafe.Pointer(hdr.Data))
fmt.Println(newData)
}
func change(a []int) []int {
a = append(a, 5)
return a
}
Run Code Online (Sandbox Code Playgroud)
这是切片的最佳部分,当附加数据超过其容量时,您需要担心其容量,因为它将指向在更大长度的内存中分配的新数组。
归档时间: |
|
查看次数: |
3468 次 |
最近记录: |