826 Stimmen

Konkateniere zwei Slices in Go

Ich versuche, den Slice [1, 2] und den Slice [3, 4] zu kombinieren. Wie kann ich das in Go machen?

Ich habe es versucht:

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

aber ich habe folgende Fehlermeldung erhalten:

kann []int-Literal (Typ []int) nicht als Typ int in append verwenden

Allerdings scheint die Dokumentation anzudeuten, dass dies möglich ist. Was übersehe ich?

slice = append(slice, anotherSlice...)

1504voto

Fügen Sie Punkte nach dem zweiten Slice hinzu:

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

Dies ist genauso wie jede andere variadische Funktion.

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

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

108voto

peterSO Punkte 146133

Anfügen und Kopieren von Slices

Die variadische Funktion append fügt null oder mehr Werte x zu s des Typs S hinzu, welcher ein Slicetyp sein muss, und gibt das resultierende Slice zurück, ebenfalls vom Typ S. Die Werte x werden an einen Parameter des Typs ...T übergeben, wobei T der Elementtyp von S ist und die entsprechenden Regeln für die Parameterübergabe gelten. Als spezieller Fall akzeptiert append auch ein erstes Argument, das dem Typ []byte zuweisbar ist, mit einem zweiten Argument vom Typ string gefolgt von .... Diese Form fügt die Bytes des Strings hinzu.

append(s S, x ...T) S  // T ist der Elementtyp von S

s0 := []int{0, 0}
s1 := append(s0, 2)        // fügt ein einzelnes Element hinzu     s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)  // fügt mehrere Elemente hinzu    s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)    // fügt ein Slice hinzu              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}

Übergabe von Argumenten an ... Parameter

Wenn f variadiisch ist mit einem finalen Parameter des Typs ...T, dann ist innerhalb der Funktion das Argument äquivalent zu einem Parameter des Typs []T. Bei jedem Aufruf von f wird das Argument, das an den finalen Parameter übergeben wird, zu einem neuen Slice des Typs []TT

Die Antwort auf deine Frage ist Beispiel s3 := append(s2, s0...) in der Go Programmiersprachenspezifikation. Zum Beispiel,

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

77voto

D.C. Joo Punkte 1077

Ich möchte @icza Antwort betonen und ein bisschen vereinfachen, da es ein entscheidendes Konzept ist. Ich gehe davon aus, dass der Leser mit Slices vertraut ist.

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

Dies ist eine gültige Antwort auf die Frage. ABER wenn Sie Slices 'a' und 'c' später im Code in einem anderen Kontext verwenden müssen, ist dies nicht der sichere Weg, um Slices zu verbinden.

Um dies zu erklären, betrachten wir den Ausdruck nicht in Bezug auf Slices, sondern in Bezug auf die zugrunde liegenden Arrays:

"Nehmen Sie das (zugrunde liegende) Array von 'a' und fügen Sie Elemente aus dem Array 'b' hinzu. Wenn das Array 'a' genügend Kapazität hat, um alle Elemente aus 'b' einzuschließen, wird das zugrunde liegende Array von 'c' kein neues Array sein, sondern tatsächlich das Array 'a'. Grundsätzlich wird der Slice 'a' len(a) Elemente des zugrunde liegenden Arrays 'a' anzeigen, und der Slice 'c' len(c) des Arrays 'a' anzeigen."

append() erstellt nicht unbedingt ein neues Array! Dies kann zu unerwarteten Ergebnissen führen. Siehe Go Playground-Beispiel.

Verwenden Sie immer die make() Funktion, wenn Sie sicherstellen möchten, dass ein neues Array für den Slice erstellt wird. Hier sind einige hässliche, aber effiziente Optionen für die Aufgabe.

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)

57voto

fiatjaf Punkte 10663

Nichts gegen die anderen Antworten, aber ich fand die kurze Erklärung in der Dokumentation verständlicher als die Beispiele darin:

func append

func append(slice []Type, elems ...Type) []Type Die eingebaute append-Funktion fügt Elemente am Ende eines Slice hinzu. Wenn der Slice ausreichend Kapazität hat, wird das Ziel neu geschnitten, um die neuen Elemente aufzunehmen. Wenn nicht, wird ein neues zugrunde liegendes Array allokiert. Append gibt den aktualisierten Slice zurück. Daher ist es notwendig, das Ergebnis von append zu speichern, oft in der Variablen, die den Slice selbst hält:

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

Als Spezialfall ist es legal, einen String an einen Byte-Slice anzuhängen, wie zum Beispiel so:

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

39voto

icza Punkte 335148

Ich denke, es ist wichtig zu betonen und zu wissen, dass, wenn der Zielslice (der Slice, an den angehängt wird) über ausreichende Kapazität verfügt, der Append "vor Ort" erfolgt, indem das Ziel neu gesliced wird (neu gesliced, um seine Länge zu erhöhen, um die anhängbaren Elemente unterzubringen).

Dies bedeutet, dass wenn das Ziel durch Slicing eines größeren Arrays oder Slices erstellt wurde, das zusätzliche Elemente über die Länge des resultierenden Slices hinaus hat, können sie überschrieben werden.

Um dies zu demonstrieren, sieh dir dieses Beispiel an:

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)

Ausgabe (versuche es auf dem 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]

Wir haben ein "Basierendes" Array a mit der Länge 10 erstellt. Dann erstellen wir den Zielslice x, indem wir dieses a Array slicen, y Slice wird durch das Composite-Literal []int{3, 4} erstellt. Nun, wenn wir y zu x anhängen, ist das Ergebnis der erwartete [1 2 3 4], aber was überraschend sein könnte, ist, dass sich auch das Basierende Array a geändert hat, da die Kapazität von x 10 beträgt, was ausreicht, um y daran anzuhängen, also wird xa verwenden wird, und append() wird Elemente von y dorthin kopieren.

Wenn Sie dies vermeiden möchten, können Sie einen vollen Slicen-Ausdruck verwenden, der die Form hat

a[low : high : max]

der einen Slice konstruiert und auch die Kapazität des resultierenden Slices steuert, indem er auf max - low gesetzt wird.

Siehe das modifizierte Beispiel (der einzige Unterschied besteht darin, dass wir x so erstellen: 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)

Ausgabe (versuche es auf dem 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]

Wie du sehen kannst, erhalten wir das gleiche Ergebnis für x, aber das basierende Array a hat sich nicht geändert, weil die Kapazität von xa[:2:2]). Um also den Append-Vorgang durchzuführen, wird ein neues Basierendes Array zugewiesen, das die Elemente von sowohl x als auch ya unterscheidet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X