679

我正在尝试将 slice[1, 2]和 slice结合起来[3, 4]。我怎样才能在 Go 中做到这一点?

我试过:

append([]int{1,2}, []int{3,4})

但得到:

cannot use []int literal (type []int) as type int in append

但是,文档似乎表明这是可能的,我错过了什么?

slice = append(slice, anotherSlice...)
4

8 回答 8

1253

在第二个切片后添加点:

//---------------------------vvv
append([]int{1,2}, []int{3,4}...)

这就像任何其他可变参数函数一样。

func foo(is ...int) {
    for i := 0; i < len(is); i++ {
        fmt.Println(is[i])
    }
}

func main() {
    foo([]int{9,8,7,6,5}...)
}
于 2013-04-27T04:12:26.887 回答
98

追加和复制切片

可变参数函数append将零个或多个值附加xs type S,它必须是切片类型,并返回结果切片,也是 type S。这些值x被传递给类型的参数,...T其中T元素类型S和相应的参数传递规则适用。作为一种特殊情况,append 还接受可分配给 type[]byte的第一个参数, string其后跟.... 这种形式附加了字符串的字节。

append(s S, x ...T) S  // T is the element type of S

s0 := []int{0, 0}
s1 := append(s0, 2)        // append a single element     s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)  // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)    // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}

将参数传递给 ... 参数

如果f是带有最终参数类型的可变参数...T,则在函数内,参数等价于类型参数[]T。在每次调用 时f,传递给最终参数的参数是一个新的类型切片,[]T其连续元素是实际参数,它们都必须可分配给类型T。因此,切片的长度是绑定到最终参数的参数的数量,并且可能因每个调用站点而异。

您的问题的答案是Go Programming Language Specifications3 := append(s2, s0...)中的示例。例如,

s := append([]int{1, 2}, []int{3, 4}...)
于 2013-04-27T12:18:59.910 回答
48

没有反对其他答案,但我发现文档中的简短解释比其中的示例更容易理解:

函数追加

func append(slice []Type, elems ...Type) []Typeappend 内置函数将元素附加到切片的末尾。如果它有足够的容量,则重新划分目标以容纳新元素。如果没有,将分配一个新的底层数组。Append 返回更新后的切片。因此有必要将 append 的结果存储在保存切片本身的变量中:

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

作为一种特殊情况,将字符串附加到字节切片是合法的,如下所示:

slice = append([]byte("hello "), "world"...)
于 2015-04-17T02:03:45.573 回答
35

我认为重要的是要指出并知道如果目标切片(您附加到的切片)具有足够的容量,则附加将通过重新切片目标(重新切片以增加其长度以便成为能够容纳可附加的元素)。

这意味着如果目标是通过切片更大的数组或切片创建的,该数组或切片具有超出结果切片长度的附加元素,它们可能会被覆盖。

为了演示,请看这个例子:

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

输出(在Go Playground上试试):

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 10
x: [1 2 3 4]
a: [1 2 3 4 0 0 0 0 0 0]

我们创建了一个a带有 length的“支持”数组10。然后我们x通过切片这个a数组来创建目标切片,y切片是使用复合文字创建的[]int{3, 4}。现在当我们追加y到时x,结果是预期的[1 2 3 4],但令人惊讶的是支持数组a也发生了变化,因为容量x足以10追加y到它,所以x重新切片也将使用相同的a支持数组,并且append()将元素复制y到那里。

如果您想避免这种情况,您可以使用具有以下形式的完整切片表达式

a[low : high : max]

它构造了一个切片,并通过将其设置为来控制结果切片的容量max - low

查看修改后的示例(唯一的区别是我们创建x这样的x = a[:2:2]::

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

输出(在Go Playground上试试)

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 2
x: [1 2 3 4]
a: [1 2 0 0 0 0 0 0 0 0]

如您所见,我们得到了相同的x结果,但后备数组a没有改变,因为容量x是“唯一的” 2(感谢完整的切片表达式a[:2:2])。因此,为了进行追加,分配了一个新的支持数组,该数组可以存储 和 的元素,这x与.ya

于 2016-10-14T07:04:10.947 回答
35

我想强调@icza 的答案并稍微简化一下,因为它是一个至关重要的概念。我假设读者熟悉slices

c := append(a, b...)

这是对该问题的有效答案。 但是,如果您稍后需要在不同上下文的代码中使用切片“a”和“c”,这不是连接切片的安全方法。

为了解释,让我们不是根据切片,而是根据底层数组来阅读表达式:

“获取'a'的(基础)数组并将数组'b'中的元素附加到它。如果数组'a'有足够的容量来包含'b'中的所有元素-'c'的基础数组将不是一个新数组,它实际上是数组'a'。基本上,切片'a'将显示底层数组'a'的len(a)个元素,切片'c'将显示数组'a'的len(c)。

append() 不一定创建一个新数组!这可能会导致意想不到的结果。请参阅Go Playground 示例

如果要确保为切片分配新数组,请始终使用 make() 函数。例如,这里有一些丑陋但足够有效的任务选项。

la := len(a)
c := make([]int, la, la + len(b))
_ = copy(c, a)
c = append(c, b...)

la := len(a)
c := make([]int, la + len(b))
_ = copy(c, a)
_ = copy(c[la:], b)
于 2019-11-06T09:22:23.833 回答
8

append( ) 函数和扩展运算符

可以使用append标准 golang 库中的方法连接两个切片。这类似于variadic函数操作。所以我们需要使用...

package main

import (
    "fmt"
)

func main() {
    x := []int{1, 2, 3}
    y := []int{4, 5, 6}
    z := append([]int{}, append(x, y...)...)
    fmt.Println(z)
}

上述代码的输出是:[1 2 3 4 5 6]

于 2018-10-04T08:47:22.697 回答
3

append([]int{1,2}, []int{3,4}...)将工作。将参数传递给...参数。

如果fis variadic with a final parameter pof type ...T,则内ftype ofp等价于 type []T

如果f在没有实际参数的情况下调用p,则传递给的p值为nil

否则,传递的值是一个新的类型切片,[]T带有一个新的底层数组,其连续元素是实际参数,它们都必须可分配给T. 因此,切片的长度和容量是绑定到p每个调用站点的参数的数量,并且可能会有所不同。

给定函数和调用

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
于 2018-02-07T06:57:08.780 回答
-1

要连接两个切片,

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{99, 100}
    s1 = append(s1, s2...)

    fmt.Println(s1) // [1 2 3 99 100]
}

将单个值附加到切片

func main() {
    s1 :=  []int{1,2,3}
    s1 := append(s1, 4)
    
    fmt.Println(s1) // [1 2 3 4]
}

将多个值附加到切片

func main() {
    s1 :=  []int{1,2,3}
    s1 = append(s1, 4, 5)
    
    fmt.Println(s1) // [1 2 3 4]
}
于 2021-11-09T10:08:47.110 回答