为了账号安全,请及时绑定邮箱和手机立即绑定

无法附加到函数内的切片

无法附加到函数内的切片

Go
慕森卡 2023-04-17 14:52:30
我试图在一个函数内向我的切片添加一个元素。我可以更改切片的元素,但不能向其添加新元素。既然切片就像参考一样,为什么我不能改变它?下面是我试过的代码:package mainimport (    "fmt")func main() {    a := []int{1, 2, 3}    change(a)    fmt.Println(a)}func change(a []int) {    a[0] = 4    a = append(a, 5)}
查看完整描述

1 回答

?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

切片是指向底层数组的指针。在 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

}

游乐场示例


或者你可以传递一个指向 slice of int 的指针,但不推荐这样做,因为 slice it 本身是一个指向引导程序数组的指针。


package main


import (

    "fmt"

)


func main() {

    a := []int{1, 2, 3}

    change(&a)

    fmt.Println(a)

}


func change(a *[]int){

    *a = append(*a, 5)

}

注意:Golang 中的一切都是按值传递的。


需要考虑的一件事是,即使您返回更新后的切片并分配给相同的值,其原始的 len 和 cap 也会发生变化,这将导致一个新的不同 len 的底层数组。尝试打印更改切片前后的长度和上限以查看差异。


fmt.Println(len(a), cap(a))

长度是切片引用的元素数。容量是底层数组中元素的数量(从切片指针引用的元素开始)。


由于底层数组将检查你可以使用反射和不安全来检查它来获取底层数组,如果在你的情况下附加数据后切片的上限发生变化,这将是不同的。


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

}

游乐场示例


这是切片最好的部分,当附加数据超过其容量时,您需要担心它的容量,因为它将指向分配在更大长度内存中的新数组。


查看完整回答
反对 回复 2023-04-17
  • 1 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信