使用扩展运算符在子切片上使用append的含义是什么?

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

What's the meaning of using append on sub-slices with spread operator?

问题

以下是代码的翻译:

我对以下代码的工作原理感到困惑,特别是对于 "..." 的目的是什么。

array = append(array[:i], array[i+1:]...)

请注意,"..." 是 Go 语言中的一种特殊语法,用于表示可变数量的参数。在这个代码中,它用于将数组中的元素进行切片操作,并将切片后的结果重新赋值给数组变量 array。具体来说,它将数组中索引为 i 的元素移除,并将移除后的切片与索引为 i 的元素之前的切片以及索引为 i 的元素之后的切片进行拼接。

英文:

I am confused about how the following code works, especially what is the purpose of "..."

array = append(array[:i], array[i+1:]...)

答案1

得分: 2

第一行代码:

a = append(a[:i], a[i+1:]...)

通过将从0到i(不包括i)和从i+1到末尾的元素组合起来,创建一个新的切片,从而从a中删除位置i处的项。

你的第二个问题是...的目的。append函数接受一个切片作为第一个参数,并且可以接受任意数量的参数,这些参数的类型都可以赋值给切片元素的类型。

append的定义如下:

func append(slice []Type, elems ...Type) []Type

写成:

a = append(a[:i], a[i+1:]...)

等同于写成:

a = append(a[:i], a[i+1], a[i+2], a[i+3], a[i+4]) // 以此类推,直到切片的末尾

使用a[i+1:]...实际上是一种简写语法,正如Go规范在<https://golang.org/ref/spec#Passing_arguments_to_..._parameters>中所描述的:

> 如果f是具有类型...T的最后一个参数p的可变参数函数,则在f内部,p的类型等效于类型[]T。如果对f的调用没有为p提供实际参数,则传递给p的值为nil。否则,传递的值是类型为[]T的新切片,其底层数组是实际参数,所有实际参数都必须可赋值给T。

Playground

英文:

The line

a = append(a[:i], a[i+1:]...)

creates a new slice by removing the item at position i in a, by combining the items from 0 to i (not included), and from i+1 to the end.

Your second question is what is the purpose of .... append accepts a slice as first argument, and an unlimited number of arguments, all with a type assignable to the type of its elements.

append is defined as

func append(slice []Type, elems ...Type) []Type

Writing

a = append(a[:i], a[i+1:]...)

is equivalent as writing

a = append(a[:i], a[i+1], a[i+2], a[i+3], a[i+4]) //and so on, until the end of the slice.

Using a[i+1:]... is basically a shorthand syntax, as the Go spec describes in <https://golang.org/ref/spec#Passing_arguments_to_..._parameters>:

> If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T. If f is invoked with no actual arguments for p, the value passed to p is nil. Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T

Playground

答案2

得分: 1

array = append(array[:i], array[i+1:]...)

是在索引i处删除一个元素

但还有一件事要指出的是,切片是由底层数组支持的。例如:

package main

import (
	"fmt"
)

func main() {
	myArray := [6]int {1,2,3,4,5,6}

	mySlice := myArray[:]

	fmt.Println("myArray before append: ", myArray)

	i := 3
	mySlice = append(mySlice[:i], mySlice[i+1:]...)

	fmt.Println("mySlice after append: ", mySlice)
	fmt.Println("myArray after append: ", myArray)
}

结果:

myArray before append:  [1 2 3 4 5 6]
mySlice after append:  [1 2 3 5 6]
myArray after append:  [1 2 3 5 6 6]

在底层,[1,2,3]保持不变,这些数据从未移动过,而由b[i+1]给出的[5,6]被附加到[1,2,3]上,从而覆盖了[3,4];其他的[6]保持不变。

即使你得到了一个不同的切片副本,底层数组仍然是相同的*,这使得append操作比如果整个底层数组都必须被复制过来要高效得多!

*如果底层数组超过其容量,将分配一个新的更大的数组,并将旧数组的值复制到新数组中,但在删除元素时永远不会发生这种情况。

英文:
array = append(array[:i], array[i+1:]...)

is removing an element at index i

but another thing to point out is that slice is backed by an underlying array. For example:

package main

import (
	&quot;fmt&quot;
)

func main() {
	myArray := [6]int {1,2,3,4,5,6}

	mySlice := myArray[:]
	
	fmt.Println(&quot;myArray before append: &quot;, myArray)
	
	i := 3
	mySlice = append(mySlice[:i], mySlice[i+1:]...)
	
	fmt.Println(&quot;mySlice after append: &quot;, mySlice)
	fmt.Println(&quot;myArray after append: &quot;, myArray)
}

Result:

myArray before append:  [1 2 3 4 5 6]
mySlice after append:  [1 2 3 5 6]
myArray after append:  [1 2 3 5 6 6]

goplayground

In the underlying [1,2,3] stayed in place, that data never go moved anywhere, while [5,6] which were given by b[i+1] were appended to [1,2,3], and thus overwrote [3,4]; the other [6] stayed in place.

Even though you get different copy of a slice the underlying array will be the same*, this makes append a much more efficient operation then if the whole underlying array had to be copied over!

*If underlying array exceeds it's capacity, a new larger array will be allocated and values from old array would be copied to the new array, but this will never happen when removing an element.

答案3

得分: 0

内置函数append是可变参数函数。

要将切片参数传递给任何可变参数函数,您需要使用...

Go语言规范:将参数传递给...参数

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


这行代码将给出一个删除位置i后的结果值。

array = append(array[:i], array[i+1:]...)

假设我们有

array := []int{1, 2, 3, 4, 5, 6, 7}
i := 3

fmt.Println("原始切片:", array)

part1 := array[:i]
part2 := array[i+1:]
fmt.Println("part1:", part1)
fmt.Println("part2:", part2)

array = append(array[:i], array[i+1:]...)
fmt.Println("结果切片:", array)

输出:

原始切片:[1 2 3 4 5 6 7]
part1:[1 2 3]
part2:[5 6 7]
结果切片:[1 2 3 5 6 7]

Play链接:https://play.golang.org/p/_cIk0VcD6w

英文:

Built-in func append is Variadic Function.

To pass slice argument to any variadic function, you have to use ...

Go lang spec: 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.


This line would give you a result value removing position i.

array = append(array[:i], array[i+1:]...)

Let's say, we have

array := []int{1, 2, 3, 4, 5, 6, 7}
i := 3

fmt.Println(&quot;Original slice:&quot;, array)

part1 := array[:i]
part2 := array[i+1:]
fmt.Println(&quot;part1:&quot;, part1)
fmt.Println(&quot;part2:&quot;, part2)

array = append(array[:i], array[i+1:]...)
fmt.Println(&quot;Result slice:&quot;, array)

Output:

Original slice: [1 2 3 4 5 6 7]
part1: [1 2 3]
part2: [5 6 7]
Result slice: [1 2 3 5 6 7]

Play Link: https://play.golang.org/p/_cIk0VcD6w

答案4

得分: 0

... 的目的是为了节省你输入单独元素的时间,因为 append 方法的第一个参数是切片,然后是要附加的元素的可变数量的参数。

也就是说,你实际上需要这样调用 append

append(sliceName[:i], array[i+1], array[i+2], array[i+3], array[i+4])

但是为了避免输入长列表的元素,你可以在切片或数组后面简单地使用 ...,将其展开为要作为参数传递的单独元素。

英文:

The purpose of ... is to save you typing individual elements as the append method takes first argument as slice and then variable number of arguments for elements to be appended.

i.e. You actually need to call append as

append(sliceName[:i], array[i+1], array[i+2], array[i+3], array[i+4])

but to avoid typing long list of elements, you can simply use ... after the slice or array to spread it as individual elements to be passed as arguments.

huangapple
  • 本文由 发表于 2017年7月20日 10:51:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/45204275.html
匿名

发表评论

匿名网友

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

确定