golang - Concatenar dos rebanadas en Go
interface en golang (6)
Estoy tratando de combinar la división [1, 2]
y la división [3, 4]
. ¿Cómo puedo hacer esto en Go?
Lo intenté:
append([]int{1,2}, []int{3,4})
pero consiguió
cannot use []int literal (type []int) as type int in append
Sin embargo, la documentación parece indicar que esto es posible, ¿qué me falta?
slice = append(slice, anotherSlice...)
La función variadic adjunta agrega cero o más valores
x
as
de tipoS
, que debe ser un tipo de sector, y devuelve el sector resultante, también del tipoS
Los valoresx
se pasan a un parámetro de tipo...T
dondeT
es el tipo de elemento deS
y se aplican las respectivas reglas de paso de parámetros. Como caso especial, anexar también acepta un primer argumento asignable al tipo[]byte
con un segundo argumento de tipostring
seguido de...
Esta forma anexa los bytes de la cadena.
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}
Pasando argumentos a ... parámetros
Si
f
es variable con el tipo de parámetro final...T
, entonces dentro de la función el argumento es equivalente a un parámetro de tipo[]T
En cada llamada def
, el argumento pasado al parámetro final es una nueva porción del tipo[]T
cuyos elementos sucesivos son los argumentos reales, que todos deben ser asignables al tipoT
La longitud de la división es, por lo tanto, el número de argumentos vinculados al parámetro final y puede diferir para cada sitio de llamada.
La respuesta a su pregunta es el ejemplo s3 := append(s2, s0...)
en la Especificación del lenguaje de programación Go . Por ejemplo,
s := append([]int{1, 2}, []int{3, 4}...)
Operador de propagación y función append ()
Se pueden concatenar dos segmentos utilizando el método de adición en la biblioteca estándar de Golang. Que es similar a la variadic
función variadic
. Así que necesitamos usar ...
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)
}
La salida del código anterior es: [1 2 3 4 5 6]
Agregue puntos después de la segunda rebanada:
//---------------------------vvv
append([]int{1,2}, []int{3,4}...)
Esto es como cualquier otra función variada.
func foo(is ...int) {
for i := 0; i < len(is); i++ {
fmt.Println(is[i])
}
}
func main() {
foo([]int{9,8,7,6,5}...)
}
Creo que es importante señalar y saber que si la división de destino (la división a la que se agrega) tiene capacidad suficiente, la adición se realizará "en el lugar", al dividir el destino (volver a dividir para aumentar su longitud para poder ser capaz de acomodar los elementos anexables).
Esto significa que si el destino se creó al cortar una matriz o segmento más grande que tiene elementos adicionales más allá de la longitud del segmento resultante, se pueden sobrescribir.
Para demostrarlo, vea este ejemplo:
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)
Salida (pruébalo en el 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]
Creamos una matriz de "respaldo" con longitud 10
. Luego creamos el segmento de destino x
dividiendo esto en a
matriz, el segmento y
se crea utilizando el literal compuesto []int{3, 4}
. Ahora, cuando agregamos y
a x
, el resultado es el esperado [1 2 3 4]
, pero lo que puede sorprender es que la matriz de respaldo a
también cambió, porque la capacidad de x
es 10
que es suficiente para añadir y
, así que x
es reslicado, que también usará la misma matriz de respaldo, y append()
copiará los elementos de y
allí.
Si desea evitar esto, puede usar una expresión de sector completa que tiene el formulario
a[low : high : max]
que construye una porción y también controla la capacidad de la porción resultante configurándola en max - low
.
Vea el ejemplo modificado (la única diferencia es que creamos x
así: 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)
Salida (pruébalo en el 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]
Como puede ver, obtenemos el mismo resultado de x
pero la matriz de respaldo a
no cambió, porque la capacidad de x
era "solo" 2
(gracias a la expresión de corte completo a[:2:2]
). Así que para hacer el anexo, se asigna una nueva matriz de respaldo que puede almacenar los elementos tanto de x
como de y
, lo que es distinto de a
.
Nada en contra de las otras respuestas, pero encontré que la explicación breve en los documentos es más fácil de entender que los ejemplos en ellos:
función adjuntar
func append(slice []Type, elems ...Type) []Type
La función incorporada append agrega elementos al final de una división. Si tiene capacidad suficiente, el destino se vuelve a segmentar para acomodar los nuevos elementos. Si no lo hace, se asignará una nueva matriz subyacente. Anexar devuelve la porción actualizada. Por lo tanto, es necesario almacenar el resultado de la anexión, a menudo en la variable que contiene la propia porción:
slice = append(slice, elem1, elem2) slice = append(slice, anotherSlice...)
Como caso especial, es legal agregar una cadena a un segmento de bytes, como este:
slice = append([]byte("hello "), "world"...)
append([]int{1,2}, []int{3,4}...)
funcionará. Pasando argumentos a ...
parámetros.
Si f
es variable con un parámetro final p
de tipo ...T
, entonces dentro de f
el tipo de p
es equivalente a tipo []T
Si f
se invoca sin argumentos reales para p
, el valor pasado a p
es nil
.
De lo contrario, el valor pasado es una nueva porción de tipo []T
con una nueva matriz subyacente cuyos elementos sucesivos son los argumentos reales, que todos deben ser asignables a T
La longitud y la capacidad de la porción es, por lo tanto, el número de argumentos enlazados a p
y pueden diferir para cada sitio de llamada.
Dada la función y las llamadas.
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")