可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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