I am confused about how the following code works, especially what is the purpose of "..."
array = append(array[:i], array[i+1:]...)
I am confused about how the following code works, especially what is the purpose of "..."
array = append(array[:i], array[i+1:]...)
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
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 (
"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)
}
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]
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.
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("Original slice:", 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("Result slice:", 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
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.