【问题标题】:Cannot append to slice inside a function [duplicate]无法附加到函数内的切片[重复]
【发布时间】:2019-03-05 01:22:33
【问题描述】:

我试图在函数内的切片中添加一个元素。我可以更改切片的元素,但不能向其中添加新元素。既然切片就像参考,为什么我不能改变它?

下面是我试过的代码:

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)
}

【问题讨论】:

  • 为此,您需要在更改函数中返回 a 并将其分配给 main `a=change(a)` 中的 a 或通过引用 func change(a *[]int) 在 go 中按值传递的结构。
  • 谢谢,工作,是否意味着我可以使用切片引用更新字段?
  • 您可以更新切片中的元素,而无需通过引用传递切片,但您不能修改切片本身(长度和容量)以更好地了解切片的工作原理blog.golang.org/go-slices-usage-and-internals

标签: pointers go slice


【解决方案1】:

切片是指向底层数组的指针。在 Golang 中有描述:

Map 和 slice 值的行为类似于指针:它们是描述符 包含指向底层映射或切片数据的指针。复制地图或 切片值不会复制它指向的数据。复制界面 value 复制存储在接口 value 中的事物。如果 接口值包含一个结构,复制接口值会生成一个 结构的副本。如果接口值持有一个指针,则复制 接口值复制了指针,但又不是 它指向的数据。

您传递的是切片的副本,而不是原始切片。返回附加到切片后的值,然后将其分配给原始切片为

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
}

Playground Example

或者你可以传递一个指向 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)
}

注意: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
}

Playground Example

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-20
    • 2020-07-06
    • 1970-01-01
    • 2016-10-01
    • 2021-08-06
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    相关资源
    最近更新 更多