Golang append an item to a slice

匿名 (未验证) 提交于 2019-12-03 02:44:02

问题:

Why does a remain the same? Does append() generate a new slice?

package main  import (     "fmt" )  var a = make([]int, 7, 8)  func Test(slice []int) {     slice = append(slice, 100)     fmt.Println(slice) }  func main() {     for i := 0; i < 7; i++ {         a[i] = i     }      Test(a)     fmt.Println(a) }

回答1:

In your example the slice argument of the Test function receives a copy of the variable a in the caller's scope.

Since a slice variable holds a "slice descriptor" which merely references an underlying array, in your Test function you modify the slice descriptor held in the slice variable several times in a row, but this does not affect the caller and its a variable.

Inside the Test function, the first append reallocates the backing array under the slice variable, copies its original contents over, appends 100 to it, and that's what you're observing. Upon exiting from Test, the slice variable goes out of scope and so does the (new) underlying array that slice references.

If you want to make Test behave like append, you have to return the new slice from it ― just like append does ― and require the callers of Test to use it in the same way they would use append:

func Test(slice []int) []int {     slice = append(slice, 100)      fmt.Println(slice)      return slice }  a = Test(a)

Please read this article thoroughly as it basically shows you how to implement append by hand, after explaining how slices are working internally. Then read this.



回答2:

Typical append usage is

a = append(a, x)

because append may either modify its argument in-place or return a copy of its argument with an additional entry, depending on the size and capacity of its input. Using a slice that was previously appended to may give unexpected results, e.g.

a := []int{1,2,3} a = append(a, 4) fmt.Println(a) append(a[:3], 5) fmt.Println(a)

may print

[1 2 3 4] [1 2 3 5]


回答3:

NOTICE that append generates a new slice if cap is not sufficient. @kostix's answer is correct, or you can pass slice argument by pointer!



回答4:

Try this, which I think makes it clear. the underlying array is changed but our slice is not, print just prints len() chars, by another slice to the cap(), you can see the changed array:

func main() {    for i := 0; i < 7; i++ {       a[i] = i   }    Test(a)    fmt.Println(a) // prints [0..6]   fmt.Println(a[:cap(a)] // prints [0..6,100] }


回答5:

In order to make your code work without having to return the slice from Test, you can pass a pointer like this:

package main  import (     "fmt" )  var a = make([]int, 7, 8)  func Test(slice *[]int) {     *slice = append(*slice, 100)      fmt.Println(*slice) }  func main() {      for i := 0; i < 7; i++ {         a[i] = i     }      Test(&a)      fmt.Println(a) }


回答6:

Go takes a more lean and lazy approach in doing this. It keeps modifying the same underlying array until the capacity of a slice is reached.

Ref: http://criticalindirection.com/2016/02/17/slice-with-a-pinch-of-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!