Concatena due sezioni in Vai


478

Sto cercando di combinare la fetta [1, 2]e la fetta [3, 4]. Come posso farlo in Go?

Provai:

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

ma ottenuto:

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

Tuttavia, la documentazione sembra indicare che ciò è possibile, cosa mi sto perdendo?

slice = append(slice, anotherSlice...)

Risposte:


879

Aggiungi punti dopo la seconda porzione:

//---------------------------vvv
append([]int{1,2}, []int{3,4}...)

Questo è proprio come qualsiasi altra funzione variadica.

func foo(is ...int) {
    for i := 0; i < len(is); i++ {
        fmt.Println(is[i])
    }
}

func main() {
    foo([]int{9,8,7,6,5}...)
}

37
append()una funzione variadica e ...consente di passare più argomenti a una funzione variadica da una sezione.

11
È assolutamente performante quando le sezioni sono piuttosto grandi? O il compilatore non passa davvero tutti gli elementi come parametri?
Rospo,

15
@Toad: in realtà non li distribuisce. Nel foo()precedente esempio, il isparametro contiene una copia della porzione originale, vale a dire che ha una copia del riferimento leggero allo stesso array sottostante, len e cap. Se la foofunzione modifica un membro, la modifica verrà visualizzata sull'originale. Ecco una demo . Quindi l'unico vero sovraccarico sarà che crea una nuova fetta se non ne avevi già una, come: foo(1, 2, 3, 4, 5)che creerà una nuova fetta che isconterrà.

2
Ah. Se ho capito bene, la funzione variadic è effettivamente implementata come una matrice di parametri (invece di ogni parametro nello stack)? E dal momento che passi nella sezione, in realtà mappa uno su uno?
Rospo,

@Toad: Sì, quando si utilizza ...su una sezione esistente, passa semplicemente quella sezione. Quando passi singoli argomenti, li raccoglie in una nuova sezione e la passa. Non ho conoscenza di prima mano della meccanica esatte, ma direi che questo: foo(1, 2, 3, 4, 5)e questo: func foo(is ...int) {Just de-zuccheri a questo: foo([]int{1, 2, 3, 4, 5})e questo: func foo(is []int) {.

77

Aggiunta e copia di sezioni

La funzione variadic appendaggiunge zero o più valori xa s di tipo S, che deve essere un tipo di sezione, e restituisce la sezione risultante, anche di tipo S. I valori xvengono passati a un parametro di tipo in ...Tcui si Ttrova il tipo di elemento Se si applicano le rispettive regole di passaggio dei parametri. Come caso speciale, append accetta anche un primo argomento assegnabile al tipo []bytecon un secondo argomento di stringtipo seguito da .... Questo modulo aggiunge i byte della stringa.

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}

Passando argomenti a ... parametri

Se fè variabile con il tipo di parametro finale ...T, allora all'interno della funzione l'argomento è equivalente a un parametro di tipo []T. Ad ogni chiamata di f, l'argomento passato al parametro finale è una nuova porzione di tipo i []Tcui elementi successivi sono gli argomenti effettivi, che devono essere tutti assegnabili al tipo T. La lunghezza della sezione è quindi il numero di argomenti associati al parametro finale e può differire per ciascun sito di chiamata.

La risposta alla tua domanda è un esempio s3 := append(s2, s0...)nella specifica del linguaggio di programmazione Go . Per esempio,

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

6
Nota: l'uso generale di append (slice1, slice2 ...) mi sembra abbastanza pericoloso. Se slice1 è una sezione di un array più grande, i valori di tale array verranno sovrascritti da slice2. (Mi fa rabbrividire che questa non sembra essere una preoccupazione comune?)
Hugo

7
@Hugo Se "passi" una porzione della tua matrice, sappi che la sezione "proprietario" sarà in grado di vedere / sovrascrivere parti della matrice che sono oltre la lunghezza corrente della fetta. Se non lo si desidera, è possibile utilizzare un'espressione di sezione intera (sotto forma di a[low : high : max]) che specifica anche la capacità massima . Ad esempio, la sezione a[0:2:4]avrà una capacità di 4e non potrà essere rislicata per includere elementi oltre a ciò, anche se l'array di supporto ha più di mille elementi dopo.
Icza,

30

Nulla contro le altre risposte, ma ho trovato la breve spiegazione nei documenti più facilmente comprensibile degli esempi in esse:

func append

func append(slice []Type, elems ...Type) []TypeLa funzione integrata append aggiunge elementi alla fine di una sezione. Se ha una capacità sufficiente, la destinazione viene rislicata per accogliere i nuovi elementi. In caso contrario, verrà assegnato un nuovo array sottostante. Aggiungi restituisce la sezione aggiornata. È quindi necessario memorizzare il risultato di append, spesso nella variabile che contiene lo slice stesso:

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

Come caso speciale, è legale aggiungere una stringa a una porzione di byte, in questo modo:

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

1
Grazie! Prezioso per me!
Korjavin Ivan,

23

Penso che sia importante sottolineare e sapere che se lo slice di destinazione (lo slice a cui si aggiunge) ha una capacità sufficiente, l'appendice avverrà "sul posto", rislicando la destinazione (cercando di aumentare la sua lunghezza per essere in grado di accogliere gli elementi appendibili).

Ciò significa che se la destinazione è stata creata tagliando un array o una sezione più grande che ha elementi aggiuntivi oltre la lunghezza della sezione risultante, potrebbero essere sovrascritti.

Per dimostrare, vedi questo esempio:

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)

Output (provalo sul 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]

Abbiamo creato un array di "supporto" acon lunghezza 10. Quindi creiamo lo xslice di destinazione tagliando questo aarray, lo yslice viene creato usando il letterale composito []int{3, 4}. Ora, quando aggiungiamo ya x, il risultato è il previsto [1 2 3 4], ma ciò può essere sorprendente è che la matrice di supporto aanche cambiato, perché la capacità di xIS 10che è sufficiente da aggiungere yad esso, così xè resliced che sarà anche utilizzare la stessa amatrice di supporto, e append()copierà gli elementi ylì dentro.

Se si desidera evitare ciò, è possibile utilizzare un'espressione di sezione completa che ha il modulo

a[low : high : max]

che costruisce una sezione e controlla anche la capacità della sezione risultante impostandola su max - low.

Vedi l'esempio modificato (l'unica differenza è che creiamo in xquesto modo 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)

Output (provalo sul 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]

Come puoi vedere, otteniamo lo stesso xrisultato ma l'array di supporto anon è cambiato, perché la capacità di xera "solo" 2(grazie all'espressione di sezione intera a[:2:2]). Quindi, per fare l'appendice, viene allocato un nuovo array di supporto che può memorizzare gli elementi di entrambi xe y, che è distinto da a.


2
È molto utile per il problema che sto affrontando. Grazie.
Aidy,

9

Vorrei sottolineare la risposta di @icza e semplificarla un po 'poiché è un concetto cruciale. Presumo che il lettore abbia familiarità con le sezioni .

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

Questa è una risposta valida alla domanda. MA se è necessario utilizzare le sezioni 'a' e 'c' nel codice in un contesto diverso, questo non è il modo sicuro per concatenare le sezioni.

Per spiegare, leggiamo l'espressione non in termini di sezioni, ma in termini di matrici sottostanti:

"Prendi l'array (sottostante) di 'a' e aggiungi elementi dall'array 'b'. Se l'array 'a' ha abbastanza capacità per includere tutti gli elementi da 'b' - l'array sottostante di 'c' non sarà un nuovo array , in realtà sarà l'array 'a'. Fondamentalmente, lo slice 'a' mostrerà len (a) elementi dell'array sottostante 'a', e lo slice 'c' mostrerà len (c) dell'array 'a'. "

append () non crea necessariamente un nuovo array! Ciò può portare a risultati imprevisti. Vedi esempio Play Goground .

Utilizzare sempre la funzione make () se si desidera assicurarsi che il nuovo array sia allocato per lo slice. Ad esempio, qui ci sono alcune opzioni abbastanza brutte ma efficienti per l'attività.

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)

Grazie per aver indicato questi effetti collaterali. Incredibilmente in contrasto con questo szenario modificato. play.golang.org/p/9FKo5idLBj4 Anche se quando si fornisce una capacità in eccesso, si dovrebbe pensare attentamente a questi sconcertanti effetti collaterali contro un'intuizione plausibile.
olippuner,

5

funzione append () e operatore spread

Due sezioni possono essere concatenate usando il appendmetodo nella libreria standard di Golang. Che è simile all'operazione di variadicfunzione. Quindi dobbiamo usare...

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

l'output del codice precedente è: [1 2 3 4 5 6]


2

append([]int{1,2}, []int{3,4}...)funzionerà. Passando argomenti ai ...parametri.

Se fè variadic con un parametro finale pdi tipo ...T, allora all'interno fdel tipo di pè equivalente al tipo []T.

Se fviene invocato senza argomenti reali per p, il valore passato a pè nil.

Altrimenti, il valore passato è una nuova porzione di tipo []Tcon un nuovo array sottostante i cui elementi successivi sono gli argomenti effettivi, a cui tutti devono essere assegnabili T. La lunghezza e la capacità della sezione sono quindi il numero di argomenti associati pe possono differire per ciascun sito di chiamata.

Data la funzione e le chiamate

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.