无法附加到函数内的切片

时间:2018-09-29 06:02:39

标签: pointers go slice

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

下面是我尝试过的代码:

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

1 个答案:

答案 0 :(得分:2)

切片是指向基础数组的指针。它在Golang中进行了描述:

  

映射和切片值的行为类似于指针:它们是   包含指向基础地图或切片数据的指针。复制地图或   slice值不会复制其指向的数据。复制界面   值复制存储在接口值中的事物的副本。如果   接口值包含一个结构,复制接口值使   结构的副本。如果接口值包含指针,则复制   接口值创建了指针的副本,但同样不是   它指向的数据。

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

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切片的指针,但是不建议这样做,因为slice本身就是一个指向引导数组的指针。

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

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