Menu

Golang Array: feste Länge, Wertsemantik, Unterschied zu Slices

Ein Go-Array hat eine feste Länge, die Teil seines Typs ist, und wird bei der Zuweisung kopiert. So deklarierst, durchläufst, vergleichst und übergibst du Arrays, und warum der meiste Go-Code stattdessen Slices nutzt.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Ein Array deklarieren

Ein Array-Typ wird [N]T geschrieben: eine Länge, dann ein Elementtyp. Die Länge steht zur Compilezeit fest und ist Teil des Typs.

Ausgabe:

[90 0 0 0 75] 5
Tue
[5]int [2 3 5 7 11]
["" "b" "" "d" ""]

Ein Array ist immer vollständig initialisiert. Elemente, die du nicht setzt, haben den Nullwert des Elementtyps: 0, "", false, nil.

Indizes und Grenzen

Indizes laufen von 0 bis len(a)-1. Ein konstanter Index außerhalb des Bereichs ist ein Compilerfehler. Ein variabler Index außerhalb des Bereichs löst zur Laufzeit eine Panic aus.

var a [3]int
a[5] = 1 // compile error: invalid argument: index 5 out of bounds [0:3]

i := 5
a[i] = 1 // panic: runtime error: index out of range [5] with length 3

Durchlaufen

for i, v := range a besucht jedes Element der Reihe nach. v ist eine Kopie des Elements, eine Zuweisung an v ändert das Array also nicht. Schreib stattdessen über den Index.

Eine Feinheit gibt es speziell bei Arrays: range über einen Array-Wert wertet vorab eine Kopie des Arrays aus. Ändert der Rumpf spätere Elemente, zeigt v trotzdem die alten Werte. Mit range über &a oder a[:] vermeidest du die Kopie.

Arrays sind Werte

Das ist der Hauptunterschied zu Arrays in C, Java oder JavaScript. Eine Zuweisung kopiert jedes Element. Auch die Übergabe an eine Funktion kopiert das Array.

Ausgabe:

[1 2 3] [99 2 3]
[1 2 3]
[0 2 3]

Bei kleinen Arrays ist das Kopieren billig, bei großen teuer: Ein [1_000_000]int als Wert zu übergeben kopiert acht Megabyte. Übergib einen Pointer (*[N]T) oder einen Slice (a[:]), wenn das Array groß ist oder die Funktion es ändern soll. Beim Indizieren über einen Array-Pointer brauchst du kein explizites *: a[0] funktioniert auf einem *[3]int.

Arrays vergleichen und als Map-Schlüssel nutzen

Arrays mit vergleichbaren Elementen unterstützen == und !=. Zwei Arrays sind gleich, wenn jedes Element gleich ist. Damit sind sie auch gültige Map-Schlüssel, Slices dagegen nicht.

Arrays unterschiedlicher Länge sind verschiedene Typen und lassen sich gar nicht vergleichen: [3]int{} == [4]int{} kompiliert nicht (mismatched types [3]int and [4]int).

Mehrdimensionale Arrays

Ein Array aus Arrays ergibt ein festes Raster. Das ganze Raster ist ein zusammenhängender Speicherblock.

row[:] macht aus der [3]rune-Zeile einen []rune-Slice, den string() akzeptiert.

Arrays vs Slices

Array [N]TSlice []T
Längefest, Teil des Typsändert sich mit append
Zuweisung und Übergabekopiert alle Elementekopiert einen kleinen Header, teilt die Elemente
NullwertN Null-Elementenil, Länge 0
==ja, Element für Elementnur gegen nil
Map-Schlüsseljanein
Typischer EinsatzDaten fester Größe: Hashes, Koordinaten, Pufferfast alles andere

In der Praxis begegnen dir Arrays vor allem an wenigen Stellen: sha256.Sum256 gibt ein [32]byte zurück, Lookup-Tabellen, deren Größe sich nie ändert, und als Speicher hinter einem Slice. Slicen eines Arrays mit a[:] oder a[1:3] erzeugt einen Slice, der sich den Speicher mit dem Array teilt; was dieses Teilen bedeutet, erklärt die Seite zu Slices.

Zwischen Arrays und Slices konvertieren

Die Konvertierung eines Slices in ein Array (Go 1.20) oder einen Array-Pointer (Go 1.17) löst eine Panic aus, wenn der Slice kürzer ist als die Array-Länge: panic: runtime error: cannot convert slice with length 2 to array or pointer to array with length 3.

Häufige Fehler

  • Erwarten, dass eine Funktion ein Array-Argument ändert. Sie bekommt eine Kopie. Übergib *[N]T oder einen Slice.
  • Ein Array verwenden, wo ein Slice erwartet wird. []int{1, 2} ist ein Slice, [2]int{1, 2} ein Array. Eine Funktion, die []int nimmt, akzeptiert kein [2]int; übergib a[:].
  • Große Arrays in einer range-Schleife. for _, v := range bigArray kopiert zuerst das ganze Array. Nimm range über &bigArray oder einen Slice.

Häufig gestellte Fragen

Wie deklariert man ein Array in Go?

Schreib die Länge in eckige Klammern vor den Elementtyp: var a [5]int ergibt fünf Nullen. Mit Werten: a := [3]string{"x", "y", "z"}. Mit [...] zählt der Compiler selbst: a := [...]int{1, 2, 3} hat den Typ [3]int.

Was ist der Unterschied zwischen einem Array und einem Slice in Go?

Ein Array hat eine feste Länge, die Teil seines Typs ist ([3]int und [4]int sind verschiedene Typen), und wird bei Zuweisung oder Übergabe kopiert. Ein Slice ([]int) ist eine Sicht auf ein darunterliegendes Array mit einer Länge, die sich durch append ändern kann, und beim Kopieren eines Slices wird nur die Sicht kopiert, nicht die Elemente. Der meiste Go-Code nutzt Slices.

Wie bekomme ich die Länge eines Arrays in Go?

Mit der eingebauten Funktion len(a). Bei einem Array ist das eine Konstante zur Compilezeit, du kannst sie also in konstanten Ausdrücken verwenden. cap(a) liefert dieselbe Zahl.

Kann man Arrays in Go vergleichen?

Ja, mit == und !=, sofern der Elementtyp vergleichbar ist. Zwei Arrays sind gleich, wenn alle ihre Elemente gleich sind. Arrays können auch Map-Schlüssel sein. Slices lassen sich nicht mit == vergleichen (außer mit nil); dafür gibt es slices.Equal.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S