Golang向切片中添加一个元素。

huangapple go评论126阅读模式
英文:

Golang append an item to a slice

问题

为什么切片 a 保持不变?append() 方法是否生成一个新的切片?

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

输出结果:

[0 1 2 3 4 5 6 100]
[0 1 2 3 4 5 6]
英文:

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

package main

import (
	&quot;fmt&quot;
)

var a = make([]int, 7, 8)

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

func main() {
	for i := 0; i &lt; 7; i++ {
		a[i] = i
	}

	Test(a)
	fmt.Println(a)
}

Output:

[0 1 2 3 4 5 6 100]
[0 1 2 3 4 5 6]

答案1

得分: 68

在你的示例中,Test 函数的 slice 参数接收了调用者作用域中变量 a副本

由于切片变量保存的是一个“切片描述符”,它只是引用底层数组,所以在 Test 函数中,你连续多次修改了 slice 变量中保存的切片描述符,但这不会影响调用者及其 a 变量。

<s>在 Test 函数内部,第一个 append 重新分配了 slice 变量下的底层数组,将其原始内容复制过来,然后将 100 追加到其中,这就是你观察到的结果。退出 Test 函数后,slice 变量超出了作用域,因此切片引用的(新的)底层数组也超出了作用域。</s>(Jeff Lee 关于这一点是正确的,所以下面是更新后的版本;正如他正确地指出的那样,这个答案 是正确的,只是可能有点简洁。)

Test 函数外部,分配了一个长度为 7、容量为 8 的切片,并填充了其中的 7 个元素。
Test 函数内部,第一个 append 发现切片的容量仍然比长度大一个元素,换句话说,还有一个元素的空间可以添加而无需重新分配。
因此,它使用这个剩余的元素,并将 100 放入其中,然后调整切片描述符的副本中的长度,使其等于切片的容量。
这不会影响调用者作用域中的切片描述符。

这就是你观察到的结果。退出 Test 函数后,slice 变量超出了作用域,因此切片引用的(新的)底层数组也超出了作用域。

如果你想让 Test 的行为像 append 一样,你必须从中返回新的切片,就像 append 一样,并要求调用 Test 的代码以与调用 append 相同的方式使用它:

func Test(slice []int) []int {
    slice = append(slice, 100)

    fmt.Println(slice)

    return slice
}

a = Test(a)

请仔细阅读这篇文章,因为它基本上向你展示了如何手动实现 append,并解释了切片的内部工作原理。然后阅读这篇文章

英文:

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.

<s>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.</s> (Jeff Lee is correct about that it's not what really happens, so the updated version follows; as he correctly states, this answer is correct, if maybe a bit too terse.)

Outside the Test function, a slice of length 7 and capacity 8 is allocated, and its 7 elements filled.
Inside the Test function, the first append sees the that the slice's capacity is still one element larger than its length — in other words, there is room for one more element to add without reallocation.
So it "eats up" that remaining element and places 100 to it, after which it adjusts the length in the copy of the slice descriptor to become equal to the slice's capaticy.
This does not affect the slice descriptor's in the caller's scope.

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 &mdash; just like append does &mdash; 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

得分: 41

典型的append用法是

a = append(a, x)

因为append根据其输入的大小和容量,可能会就地修改其参数,也可能会返回一个带有额外条目的参数副本。使用先前附加的切片可能会产生意外的结果,例如

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

可能会打印出

[1 2 3 4]
[1 2 3 5]
英文:

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

得分: 13

为了使你的代码在不返回Test函数中的切片的情况下工作,你可以像这样传递一个指针:

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

这段代码中,我们定义了一个切片a,并将其传递给Test函数的指针。在Test函数中,我们使用指针解引用的方式对切片进行操作,并将值追加到切片中。最后,我们在main函数中打印切片的值。

英文:

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 (
    &quot;fmt&quot;
)

var a = make([]int, 7, 8)

func Test(slice *[]int) {
    *slice = append(*slice, 100)

    fmt.Println(*slice)
}

func main() {

    for i := 0; i &lt; 7; i++ {
        a[i] = i
    }

    Test(&amp;a)

    fmt.Println(a)
}

答案4

得分: 6

请注意,如果容量不足,append 会生成一个新的切片。@kostix的回答是正确的,或者你可以通过指针传递 slice 参数!

英文:

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!

答案5

得分: 5

尝试这个,我认为它会更清晰。底层数组被改变了,但是我们的切片没有被改变,print只打印了len()个字符,通过另一个切片到cap(),你可以看到改变后的数组:

func main() {

  for i := 0; i < 7; i++ {
      a[i] = i
  }

  Test(a)

  fmt.Println(a) // 打印 [0..6]
  fmt.Println(a[:cap(a)]) // 打印 [0..6,100]
}
英文:

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 &lt; 7; i++ {
      a[i] = i
  }

  Test(a)

  fmt.Println(a) // prints [0..6]
  fmt.Println(a[:cap(a)] // prints [0..6,100]
}

答案6

得分: 3

 main

import (
    "fmt"
)

var a = make([]int, 7, 8)
// 切片是数组段的描述符。
// 它由指向数组的指针、段的长度和其容量(段的最大长度)组成。
// 长度是切片引用的元素数量。
// 容量是底层数组中的元素数量(从切片指针引用的元素开始)。
// |-&gt; 参考:https://blog.golang.org/go-slices-usage-and-internals -&gt; "Slice internals" 部分

func Test(slice []int) {
    // 切片接收到一个指向与切片 `a` 相同数组的切片 `slice` 的副本
    slice[6] = 10
    slice = append(slice, 100)
    // 由于 `slice` 的容量为 8,长度为 7,它可以添加 100 并使长度为 8
    fmt.Println(slice, len(slice), cap(slice), " &lt;&lt; Test 1")
    slice = append(slice, 200)
    // 由于 `slice` 的容量为 8,长度也为 8,切片必须创建一个新的切片
    // - 容量为原来的两倍,并指向新数组(参见下面的引用 1)。
    // (我也感到困惑,为什么不是 (n+1)*2=20。但是创建一个容量为 16 的新切片)。
    slice[6] = 13 // 确保它是一个新切片 :)
    fmt.Println(slice, len(slice), cap(slice), " &lt;&lt; Test 2")
}

func main() {
    for i := 0; i < 7; i++ {
        a[i] = i
    }

    fmt.Println(a, len(a), cap(a))
    Test(a)
    fmt.Println(a, len(a), cap(a))
    fmt.Println(a[:cap(a)], len(a), cap(a))
    // fmt.Println(a[:cap(a)+1], len(a), cap(a)) -&gt; 这将不起作用
}

输出:

[0 1 2 3 4 5 6] 7 8
[0 1 2 3 4 5 10 100] 8 8  &lt;&lt; Test 1
[0 1 2 3 4 5 13 100 200] 9 16  &lt;&lt; Test 2
[0 1 2 3 4 5 10] 7 8
[0 1 2 3 4 5 10 100] 7 8

引用 1:https://blog.golang.org/go-slices-usage-and-internals

func AppendByte(slice []byte, data ...byte) []byte {
    m := len(slice)
    n := m + len(data)
    if n > cap(slice) { // 如果需要,重新分配
        // 分配所需的两倍空间,以备将来增长。
        newSlice := make([]byte, (n+1)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}

<details>
<summary>英文:</summary>

Explanation (read inline comments):

```go

package main

import (
    &quot;fmt&quot;
)

var a = make([]int, 7, 8)
// A slice is a descriptor of an array segment. 
// It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).
// The length is the number of elements referred to by the slice.
// The capacity is the number of elements in the underlying array (beginning at the element referred to by the slice pointer).
// |-&gt; Refer to: https://blog.golang.org/go-slices-usage-and-internals -&gt; &quot;Slice internals&quot; section

func Test(slice []int) {
    // slice receives a copy of slice `a` which point to the same array as slice `a`
    slice[6] = 10
    slice = append(slice, 100)
    // since `slice` capacity is 8 &amp; length is 7, it can add 100 and make the length 8
    fmt.Println(slice, len(slice), cap(slice), &quot; &lt;&lt; Test 1&quot;)
    slice = append(slice, 200)
    // since `slice` capacity is 8 &amp; length also 8, slice has to make a new slice 
    // - with double of size with point to new array (see Reference 1 below).
    // (I&#39;m also confused, why not (n+1)*2=20). But make a new slice of 16 capacity).
    slice[6] = 13 // make sure, it&#39;s a new slice :)
    fmt.Println(slice, len(slice), cap(slice), &quot; &lt;&lt; Test 2&quot;)
}

func main() {
    for i := 0; i &lt; 7; i++ {
        a[i] = i
    }

    fmt.Println(a, len(a), cap(a))
    Test(a)
    fmt.Println(a, len(a), cap(a))
    fmt.Println(a[:cap(a)], len(a), cap(a))
    // fmt.Println(a[:cap(a)+1], len(a), cap(a)) -&gt; this&#39;ll not work
}

Output:

[0 1 2 3 4 5 6] 7 8
[0 1 2 3 4 5 10 100] 8 8  &lt;&lt; Test 1
[0 1 2 3 4 5 13 100 200] 9 16  &lt;&lt; Test 2
[0 1 2 3 4 5 10] 7 8
[0 1 2 3 4 5 10 100] 7 8

Reference 1: https://blog.golang.org/go-slices-usage-and-internals

func AppendByte(slice []byte, data ...byte) []byte {
    m := len(slice)
    n := m + len(data)
    if n &gt; cap(slice) { // if necessary, reallocate
        // allocate double what&#39;s needed, for future growth.
        newSlice := make([]byte, (n+1)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}

答案7

得分: 2

Go在处理这个问题时采取了更加精简和懒惰的方法。它会不断修改同一个底层数组,直到切片的容量达到上限。

参考:http://criticalindirection.com/2016/02/17/slice-with-a-pinch-of-salt/

链接中的示例输出解释了Go中切片的行为。

创建切片a。

切片a 长度=7 容量=7 [0 0 0 0 0 0 0]

切片b引用切片a中的索引2、3、4。因此,容量为5(= 7-2)。

b := a[2:5]
切片b 长度=3 容量=5 [0 0 0]

修改切片b也会修改切片a,因为它们指向同一个底层数组。

b[0] = 9
切片a 长度=7 容量=7 [0 0 9 0 0 0 0]
切片b 长度=3 容量=5 [9 0 0]

向切片b追加1。覆盖了切片a。

切片a 长度=7 容量=7 [0 0 9 0 0 1 0]
切片b 长度=4 容量=5 [9 0 0 1]

向切片b追加2。覆盖了切片a。

切片a 长度=7 容量=7 [0 0 9 0 0 1 2]
切片b 长度=5 容量=5 [9 0 0 1 2]

向切片b追加3。在这里,由于容量超载,会创建一个新的副本。

切片a 长度=7 容量=7 [0 0 9 0 0 1 2]
切片b 长度=6 容量=12 [9 0 0 1 2 3]

验证在前一步中容量超载后,切片a和切片b是否指向不同的底层数组。

b[1] = 8
切片a 长度=7 容量=7 [0 0 9 0 0 1 2]
切片b 长度=6 容量=12 [9 8 0 1 2 3]
英文:

> 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-salt/

Output of the example from the link explains the behavior of slices in Go.

Creating slice a.

Slice a len=7 cap=7 [0 0 0 0 0 0 0]

Slice b refers to the 2, 3, 4 indices in slice a. Hence, the capacity is 5 (= 7-2).

b := a[2:5]
Slice b len=3 cap=5 [0 0 0]

Modifying slice b, also modifies a, since they are pointing to the same underlying array.

b[0] = 9
Slice a len=7 cap=7 [0 0 9 0 0 0 0]
Slice b len=3 cap=5 [9 0 0]

Appending 1 to slice b. Overwrites a.

Slice a len=7 cap=7 [0 0 9 0 0 1 0]
Slice b len=4 cap=5 [9 0 0 1]

Appending 2 to slice b. Overwrites a.

Slice a len=7 cap=7 [0 0 9 0 0 1 2]
Slice b len=5 cap=5 [9 0 0 1 2]

Appending 3 to slice b. Here, a new copy is made as the capacity is overloaded.

Slice a len=7 cap=7 [0 0 9 0 0 1 2]
Slice b len=6 cap=12 [9 0 0 1 2 3]

Verifying slices a and b point to different underlying arrays after the capacity-overload in the previous step.

b[1] = 8
Slice a len=7 cap=7 [0 0 9 0 0 1 2]
Slice b len=6 cap=12 [9 8 0 1 2 3]

答案8

得分: 2

package main

import (
	"fmt"
)

func a() {
	x := []int{}
	x = append(x, 0)
	x = append(x, 1)  // commonTags := labelsToTags(app.Labels)
	y := append(x, 2) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	z := append(x, 3) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	fmt.Println(y, z)
}

func b() {
	x := []int{}
	x = append(x, 0)
	x = append(x, 1)
	x = append(x, 2)  // commonTags := labelsToTags(app.Labels)
	y := append(x, 3) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	z := append(x, 4) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	fmt.Println(y, z)
}

func main() {
	a()
	b()
}

首先的猜测可能是:

[0, 1, 2] [0, 1, 3]
[0, 1, 2, 3] [0, 1, 2, 4]

但实际结果是:

[0, 1, 2] [0, 1, 3]
[0, 1, 2, 4] [0, 1, 2, 4]

更多细节请参考:https://allegro.tech/2017/07/golang-slices-gotcha.html

英文:
package main

import (
	&quot;fmt&quot;
)

func a() {
	x := []int{}
	x = append(x, 0)
	x = append(x, 1)  // commonTags := labelsToTags(app.Labels)
	y := append(x, 2) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	z := append(x, 3) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	fmt.Println(y, z)
}

func b() {
	x := []int{}
	x = append(x, 0)
	x = append(x, 1)
	x = append(x, 2)  // commonTags := labelsToTags(app.Labels)
	y := append(x, 3) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	z := append(x, 4) // Tags: append(commonTags, labelsToTags(d.Labels)...)
	fmt.Println(y, z)
}

func main() {
	a()
	b()
}

First guess could be

[0, 1, 2] [0, 1, 3]
[0, 1, 2, 3] [0, 1, 2, 4]

but in fact it results in

[0, 1, 2] [0, 1, 3]
[0, 1, 2, 4] [0, 1, 2, 4]

Golang向切片中添加一个元素。

Golang向切片中添加一个元素。

More details see https://allegro.tech/2017/07/golang-slices-gotcha.html

答案9

得分: 2

append()函数在没有足够容量的情况下会返回一个新的底层数组。在你的例子中,

var a = make([]int, 7, 8)

你分配了一个切片(长度为7)的底层数组(容量为8)给变量a,然后将其作为参数slice传递给函数。当调用append()时,它发现容量为1,然后只需将slicelen从7更新为8,并将值100放入该位置。

切片a与切片slice不同,它们具有不同的len属性。lencap是切片的属性,而不是底层数组的属性。更多详情请参考:切片是按值传递的吗?

运行下面的示例:

package main

import (
    "fmt"
)

var a = make([]int, 7, 8)

func Test(slice []int) {
    fmt.Printf("slice的地址是 %p\n", &slice)
    fmt.Println("slice: cap=", cap(slice), "len=", len(slice))
    slice = append(slice, 100)
    fmt.Println("slice: cap=", cap(slice), "len=", len(slice))
    fmt.Println(slice)
}

func main() {
    for i := 0; i < 7; i++ {
        a[i] = i
    }
    fmt.Printf("a的地址是 %p\n", &a)
    fmt.Println("a: cap=", cap(a), "len=", len(a))
    Test(a)
    fmt.Println("a: cap=", cap(a), "len=", len(a))
    fmt.Println(a)
    fmt.Println(a[:8]) // 手动将a的len扩展到8的cap
}

结果是:

a的地址是 0x2cbfc0
a: cap= 8 len= 7
slice的地址是 0xc000098060
slice: cap= 8 len= 7
slice: cap= 8 len= 8
[0 1 2 3 4 5 6 100]
a: cap= 8 len= 7
[0 1 2 3 4 5 6]
[0 1 2 3 4 5 6 100]
英文:

Answer: append() will return new underlying array if has no sufficient capacity. In your example,

var a = make([]int, 7, 8)

You allocate a slice (length is 7)of an underlying array(capacity is 8) to a, then pass it to function as parameter slice. When append() is called, it found the 1 capacity, then just update the slice's len from 7 to 8 and put the value 100 into that position.

The slice a is different to the slice slice, having different len property. len and cap are the property of slice, not the underlying array. For more details: Are slices passed by value?.

Run the example below:

package main

import (
    &quot;fmt&quot;
)

var a = make([]int, 7, 8)

func Test(slice []int) {
    fmt.Printf(&quot;slice&#39;s address is %p\n&quot;, &amp;slice)
    fmt.Println(&quot;slice: cap=&quot;,cap(slice),&quot;len=&quot;,len(slice))
    slice = append(slice, 100)
    fmt.Println(&quot;slice: cap=&quot;,cap(slice),&quot;len=&quot;,len(slice))
    fmt.Println(slice)
}

func main() {
    for i := 0; i &lt; 7; i++ {
        a[i] = i
    }
    fmt.Printf(&quot;a&#39;s address is %p\n&quot;, &amp;a)
    fmt.Println(&quot;a: cap=&quot;,cap(a),&quot;len=&quot;,len(a))
    Test(a)
    fmt.Println(&quot;a: cap=&quot;,cap(a),&quot;len=&quot;,len(a))
    fmt.Println(a)
    fmt.Println(a[:8]) // manully extend a&#39;s len to cap of 8
}

Result is:

❯❯  Temp  17:33  go run .\test.go
a&#39;s address is 0x2cbfc0
a: cap= 8 len= 7
slice&#39;s address is 0xc000098060
slice: cap= 8 len= 7
slice: cap= 8 len= 8
[0 1 2 3 4 5 6 100]
a: cap= 8 len= 7
[0 1 2 3 4 5 6]
[0 1 2 3 4 5 6 100]

答案10

得分: 1

我认为原始答案并不完全正确。即使底层数组发生了改变,append()函数同时改变了切片和底层数组,但底层数组仍然被两个切片共享。

根据Go文档的说明:

> 切片不存储任何数据,它只是描述底层数组的一个部分。(链接)

切片只是数组的包装值,意味着它们包含有关如何切片底层数组的信息,用于存储一组数据。因此,默认情况下,当将切片传递给另一个方法时,实际上是按值传递,而不是按引用/指针传递,尽管它们仍然使用相同的底层数组。通常,数组也是按值传递的,所以我认为切片指向底层数组而不是将其存储为值。关于你的问题,当你将切片传递给以下函数时:

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

你实际上传递了切片的副本以及指向相同底层数组的指针。这意味着你对slice所做的更改不会影响main函数中的切片。切片本身存储了有关它切片了多少个数组元素以及向公共部分公开了多少的信息。因此,当你运行append(slice, 1000)时,虽然扩展了底层数组,但也改变了slice的切片信息,这些信息在Test()函数中是私有的。

然而,如果你将代码更改如下,它可能会起作用:

func main() {
    for i := 0; i < 7; i++ {
        a[i] = i
    }

    Test(a)
    fmt.Println(a[:cap(a)])
}

原因是你通过使用a[:cap(a)]对其已更改的底层数组进行了切片扩展,这是由Test()函数改变的。如下所述:

> 只要切片有足够的容量,就可以通过重新切片来扩展切片的长度。(链接)

英文:

I think the original answer is not exactly correct. append() changed both the slices and the underlying array even though the underlying array is changed but still shared by both of the slices.

As specified by the Go Doc:

> A slice does not store any data, it just describes a section of an underlying array. (Link)

Slices are just wrapper values around arrays, meaning that they contain information about how they slice an underlying array which they use to store a set of data. Therefore, by default, a slice, when passed to another method, is actually passed by value, instead of reference/pointer even though they will still be using the same underlying array. Normally, arrays are also passed by value too, so I assume a slice points at an underlying array instead of store it as a value. Regarding your question, when you run passed your slice to the following function:

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

you actually passed a copy of your slice along with a pointer to the same underlying array.That means, the changes you did to the slice didn't affect the one in the main function. It is the slice itself which stores the information regarding how much of an array it slices and exposes to the public. Therefore, when you ran append(slice, 1000), while expanding the underlying array, you also changed slicing information of slice too, which was kept private in your Test() function.

However, if you have changed your code as follows, it might have worked:

func main() {
    for i := 0; i &lt; 7; i++ {
        a[i] = i
    }

    Test(a)
    fmt.Println(a[:cap(a)])
}

The reason is that you expanded a by saying a[:cap(a)] over its changed underlying array, changed by Test() function. As specified here:

> You can extend a slice's length by re-slicing it, provided it has sufficient capacity. (Link)

答案11

得分: 1

是的,当你使用append()函数向切片中添加值时,通常会创建一个新的切片,而不是覆盖原始的切片。

请查看下面的代码片段:

package main

import "fmt"

func main() {

    var ages = []int{3,6,8,1,9}

    fmt.Println(append(ages, 13))

    fmt.Println("原始切片仍然是:", ages)
}

如果你想要覆盖原始的切片,你需要将append()函数的返回值赋给切片名,如下所示:

ages = append(ages, 12)
fmt.Println("现在原始切片是:", ages)
英文:

Yes, when you use the append(), to add values to a Slice, it usually creates a new Slice and doesn't overwrite the original Slice.

Check the below code snippet

package main

import &quot;fmt&quot;

func main() {

	var ages = []int{3,6,8,1,9}

	fmt.Println(append(ages, 13))

	fmt.Println(&quot;Original Slice is still: &quot;, ages)
}

If you need to overwrite the original Slice, you need to set the append() to the Slice name as below.

ages = append(ages, 12)
fmt.Println(&quot;Now original Slice is: &quot;, ages)

答案12

得分: 1

非常简单。

1)如果切片的容量足够进行追加操作,那么就使用现有的底层数组。

2)如果切片的容量不足以进行追加操作,那么就创建一个新的底层数组。

英文:

Very simple.

  1. If the capacity of the slice is enough to append, then just use the existing underlying array.

  2. If the capacity of the slice is not enough to append, then create a new underlying array.

答案13

得分: 0

这是一个很好的切片追加的实现。我猜这与底层的实现方式相似:

package main

import "fmt"

func main() {
    slice1 := []int{0, 1, 2, 3, 4}
    slice2 := []int{55, 66, 77}
    fmt.Println(slice1)
    slice1 = Append(slice1, slice2...) // The '...' is essential!
    fmt.Println(slice1)
}

// Append ...
func Append(slice []int, items ...int) []int {
    for _, item := range items {
        slice = Extend(slice, item)
    }
    return slice
}

// Extend ...
func Extend(slice []int, element int) []int {
    n := len(slice)
    if n == cap(slice) {
        // Slice is full; must grow.
        // We double its size and add 1, so if the size is zero we still grow.
        newSlice := make([]int, len(slice), 2*len(slice)+1)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0 : n+1]
    slice[n] = element
    return slice
}

这段代码实现了切片的追加功能。通过调用Append函数,可以将一个切片追加到另一个切片的末尾。在Append函数中,使用Extend函数来逐个追加元素到切片中。Extend函数会检查切片是否已满,如果已满,则会创建一个新的切片,并将原有切片的元素复制到新切片中。然后,将要追加的元素添加到新切片的末尾,并返回新切片。

希望对你有帮助!

英文:

Here is a nice implementation of append for slices. I guess its similar to what is going on under the hood:

package main

import &quot;fmt&quot;

func main() {
	slice1 := []int{0, 1, 2, 3, 4}
	slice2 := []int{55, 66, 77}
	fmt.Println(slice1)
	slice1 = Append(slice1, slice2...) // The &#39;...&#39; is essential!
	fmt.Println(slice1)
}

// Append ...
func Append(slice []int, items ...int) []int {
	for _, item := range items {
		slice = Extend(slice, item)
	}
	return slice
}

// Extend ...
func Extend(slice []int, element int) []int {
	n := len(slice)
	if n == cap(slice) {
		// Slice is full; must grow.
		// We double its size and add 1, so if the size is zero we still grow.
		newSlice := make([]int, len(slice), 2*len(slice)+1)
		copy(newSlice, slice)
		slice = newSlice
	}
	slice = slice[0 : n+1]
	slice[n] = element
	return slice
}

答案14

得分: 0

追加到切片的末尾,如果切片为空,则创建一个新条目

// in := [][]int{{}}, in := [][]int{{1,3},{2,3}}
// addtoEndofSliceArray(in,10)
// out=[[10]], out=[[1,3],[2,3,10]]

func addtoEndofSliceArray(in [][]int, element int) (out [][]int) {
	if len(in) > 0 {
		k := in[len(in)-1]
		k = append(k, element)
		in = in[:len(in)-1]
		in = append(in, k)
	} else {
		in = [][]int{{element}}
	}
	return in
}

将元素追加到切片的末尾,如果切片不为空,则将元素添加到最后一个子切片中;如果切片为空,则创建一个只包含该元素的新子切片。

英文:

Append to end of a slice, or create a new entry if slice is empty

// in := [][]int{{}}, in := [][]int{{1,3},{2,3}}
// addtoEndofSliceArray(in,10)
// out=[[10]], out=[[1,3],[2,3,10]]

func addtoEndofSliceArray(in [][]int,element int)(out [][]int){
	if len(in) &gt;0 {
		k :=in[len(in)-1]
		k = append(k,element)
		in = in[:len(in)-1]
		in = append(in, k)
	}else{
		in = [][]int{{element}}
	}
	return in
}

huangapple
  • 本文由 发表于 2013年11月25日 22:14:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/20195296.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定