我试图将切片[1,2]和切片[3,4]结合起来。我如何在围棋中做到这一点?

我试着:

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

但有:

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

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

slice = append(slice, anotherSlice...)

在第二片之后加点:

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

Appending to and copying slices The variadic function append appends zero or more values x to s of type S, which must be a slice type, and returns the resulting slice, also of type S. The values x are passed to a parameter of type ...T where T is the element type of S and the respective parameter passing rules apply. As a special case, append also accepts a first argument assignable to type []byte with a second argument of string type followed by .... This form appends the bytes of the 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 If f is variadic with final parameter type ...T, then within the function the argument is equivalent to a parameter of type []T. At each call of f, the argument passed to the final parameter is a new slice of type []T whose successive elements are the actual arguments, which all must be assignable to the type T. The length of the slice is therefore the number of arguments bound to the final parameter and may differ for each call site.

你问题的答案是Go编程语言规范中的示例s3:= append(s2, s0…)例如,

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

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

func append func append(slice []Type, elems ...Type) []Type The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself: slice = append(slice, elem1, elem2) slice = append(slice, anotherSlice...) As a special case, it is legal to append a string to a byte slice, like this: slice = append([]byte("hello "), "world"...)


我认为重要的是要指出并知道,如果目标片(你追加的片)有足够的容量,追加将“原地”发生,通过重切片目的地(重切片增加它的长度,以便能够容纳可追加的元素)。

这意味着如果目标是通过切片一个更大的数组或切片创建的,其中有超出结果切片长度的额外元素,它们可能会被覆盖。

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

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。然后我们通过将这个数组切片来创建x目标切片,y切片使用复合文字[]int{3,4}创建。现在,当我们将y追加到x时,结果是预期的[1 2 3 4],但可能令人惊讶的是,后备数组a也发生了变化,因为x的容量为10,这足以将y追加到它,因此x被重新分割,这也将使用相同的后备数组,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和y的元素,这与a是不同的。


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

如果f是可变的,最终参数p类型为…T,那么在f内p的类型等价于类型[]T。

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

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

给定函数和调用

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

Append()函数和展开运算符

可以使用标准golang库中的append方法连接两个片。这类似于变进函数的运算。所以我们需要用…

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]


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

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

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

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

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

要连接两个切片,

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

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

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