在Go语言中连接两个切片

x759pob2  于 2022-12-07  发布在  Go
关注(0)|答案(9)|浏览(106)

我想把切片[1, 2]和切片[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...)
omvjsjqw

omvjsjqw1#

在第二个切片后添加点:

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

jexiocij2#

追加到切片并复制切片
变量函数append将零个或多个值x附加到S类型的s(必须是切片类型),并返回结果切片。也是S类型。值x传递给...T类型的参数,其中TS的元素类型,并且相应的参数传递规则适用。作为特殊情况,append还接受第一个参数可赋值为[]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类型。因此,切片的长度是绑定到final参数的参数的数目,并且对于每个调用位置可能不同。
您问题的答案是Go Programming Language Specification中的s3 := append(s2, s0...)示例。例如,

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

o2rvlv0m3#

其他的答案没有什么不对的,但是我发现文档中的简短解释比其中的例子更容易理解:

函数附加

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

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

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

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

pu3pd22g4#

我想强调一下@icza答案,并将其简化一些,因为它是一个至关重要概念。

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

这是问题的有效答案。但是如果您稍后需要在不同上下文中的代码中使用切片'a'和'c',则这不是连接切片的安全方法。
为了解释,让我们不以切片的形式,而是以底层数组的形式来阅读表达式:
获取“a”得(基础)数组,并将数组“B”中得元素追加到其中.如果数组“a”有足够得容量包含“b”中得所有元素-基础数组“c”将不是一个新数组,它实际上是数组“a.”基本上,切片“a”将显示基础数组“a”得len(a)元素,切片“c”将显示数组“a”得len(c).
append()不一定会创建新数组!这可能会导致意外的结果。请参阅Go Playground example

如果你想确保新的数组被分配给切片,总是使用make()函数。例如,这里有一些丑陋但足够有效的选项。

第一次

2nbm6dog

2nbm6dog5#

我认为有必要指出并了解,如果目标切片(您追加到的切片)有足够的容量,则追加将通过重新切片目标(重新切片以 * 增加 * 其长度,以便能够容纳可追加的元素)“就地”发生。
这意味着,如果目标是通过对更大的数组或切片进行切片而创建的,而该数组或切片具有超出结果切片长度的其他元素,则这些元素可能会被覆盖。
要进行演示,请参见以下示例:

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]

我们创建了一个长度为10的“支持”数组a。然后,我们通过对这个a数组进行切片来创建x目标切片。y切片是使用复合文字[]int{3, 4}创建的。现在,当我们将y追加到x时,结果就是预期的[1 2 3 4]。但令人惊讶的是,后备阵列x1M9N1x也改变了,因为x1M10N1x的容量是x1M11N1x,这足以将x1M12N1x附加到其上,所以x1M13N1x被重新分片,这也将使用相同的x1M14N1x后备阵列,并且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])。因此,为了执行追加,分配了一个新的后备数组,该数组可以存储xy的元素,其不同于a

yduiuuwa

yduiuuwa6#

append()函数和spread运算符

可以使用标准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]

pexxcrt2

pexxcrt27#

似乎是泛型的完美用途(如果使用1.18或更高版本)。

func concat[T any](first []T, second []T) []T {
    n := len(first);
    return append(first[:n:n], second...);
}
b91juud3

b91juud38#

要连接两个切片,

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]
}
c9qzyr3d

c9qzyr3d9#

append([]int{1,2}, []int{3,4}...)将起作用。将参数传递给...参数。
如果f是可变变量,其最后一个参数p的类型为...T,则在f中,p的类型等效于[]T的类型。
如果调用f时没有p的实际参数,则传递给p的值为nil
否则,传递的值是一个[]T类型的新切片,它具有一个新的基础数组,该数组的连续元素是实际参数,这些参数都必须可赋值给T。因此,切片的长度和容量是绑定到p的参数的数量,并且对于每个调用位置可能不同。
给定函数和调用

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

相关问题