在Go中连接两个切片

时间:2013-04-27 04:08:41

标签: go append slice variadic-functions

我正在尝试将切片[1, 2]和切片[3, 4]组合在一起。我怎么能在Go中做到这一点?

我试过了:

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

但得到了:

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

然而,the documentation似乎表明这是可能的,我缺少什么?

slice = append(slice, anotherSlice...)

7 个答案:

答案 0 :(得分:596)

在第二个切片后添加点:

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

答案 1 :(得分:60)

  

Appending to and copying slices

     

可变函数append将零个或多个值x追加到s   类型S,必须是切片类型,并返回结果   切片,也是S类型。值x将传递给参数   键入...T,其中TS的元素类型和相应的元素类型   参数传递规则适用。作为一个特例,追加也接受   第一个可赋值给[]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}
     

Passing arguments to ... parameters

     

如果f是最终参数类型为...T的可变参数,则在。{   function该参数等效于[]T类型的参数。在   每次调用f时,传递给最终参数的参数都是新的   类型为[]T的切片,其连续元素是实际参数,   所有必须分配给T类型。切片的长度是   因此,绑定到最终参数的参数的数量可以   每个呼叫站点都有所不同。

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

s := append([]int{1, 2}, []int{3, 4}...)

答案 2 :(得分:25)

没有其他答案,但我发现the docs中的简短解释比其中的例子更容易理解:

  

func追加

     

func append(slice []Type, elems ...Type) []Type附加内置版   function将元素附加到切片的末尾。如果它已经足够了   容量,目的地被重新调整以适应新元素。   如果没有,将分配新的底层数组。附加   返回更新的切片。因此有必要存储   追加的结果,通常在持有切片本身的变量中:

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

作为一种特殊情况,将字符串附加到字节切片是合法的,   像这样:

slice = append([]byte("hello "), "world"...)

答案 3 :(得分:19)

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

这意味着如果目的地是通过切割一个更大的数组或切片来创建的,这个数组或切片的元素超出了生成的切片的长度,它们可能会被覆盖。

要演示,请参阅此示例:

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的“支持”数组10。然后,我们通过对此x数组进行切片来创建a目标切片,使用复合文字y创建[]int{3, 4}切片。现在,当我们将y追加到x时,结果就是预期的[1 2 3 4],但可能令人惊讶的是支持数组a也发生了变化,因为{{{}}的容量1}}是x,足以向其10附加y,因此x会被重置,也会使用相同的a支持数组,append()会将y的元素复制到那里。

如果您想避免这种情况,可以使用格式为

full slice expression
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])。因此,为了执行追加,会分配一个新的支持数组,可以存储xy的元素,这些元素与a不同。

答案 4 :(得分:4)

append()函数和扩展运算符

可以使用标准golang库中的 append 方法来连接两个切片。这类似于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]

答案 5 :(得分:4)

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

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

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

为说明起见,让我们不要根据切片来读取表达式,而要根据底层数组来读取表达式:

  

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

append()不一定会创建一个新数组!这可能会导致意外结果。参见Go Playground example

如果要确保为切片分配新数组,请始终使用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)

答案 6 :(得分:1)

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

如果f为变量型,其最终参数p的类型为...T,那么fp的类型等同于[]T的类型}}。

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

否则,传递的值是类型为[]T的新切片,其中包含一个新的基础数组,其连续元素是实际参数,所有这些参数都必须可分配给T。因此,切片的长度和容量是绑定到p的参数数量,并且可能因每个呼叫站点而不同。

给定功能并调用

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")