Slices
Slices sind sogenannte Felder, also eine Aneinanderreihung von Datentypen, die man über einen fortlaufenden Zähler (Index) auswählen kann. Was sich kompliziert anhört, ist vom Aufbau her ganz einfach. Beispielsweise sind die Tage in einem Monat über einen Index auswählbar (»der 13. Tag im Oktober«). Oder Häuser in einer Straße (»Haus Nr. 117«). Auch werden Dateien von der Festplatte Byte für Byte eingelesen und als Byte-Slices gespeichert. Es kann aber jeder beliebige Datentyp in einem Feld gespeichert werden.
Im Unterschied zu unserer gewohnten Zählweise beginnt Go mit der Zahl 0 an zu zählen. D.h. das erste Element in einer Reihe wird über den Index 0 angesprochen:
package main
import "fmt"
func main() {
jahreszeiten := []string{"Frühling", "Sommer", "Herbst", "Winter"}
// Schreibt "Sommer" auf die Konsole, nicht "Frühling!"
fmt.Println(jahreszeiten[1])
}
Die Länge eines slice
kann man mit der eingebauten Funktion len()
feststellen. Das Feld jahreszeiten
aus dem Beispiel hat
erwartungsgemäß die Länge 4. Vorsicht: Wenn du versuchst auf einen Index
zuzugreifen, der nicht erlaubt ist (im Beispiel wäre das -1 oder kleiner bzw.
4 oder größer), dann wird ein Laufzeitfehler erzeugt (eine sogenannte panic
, siehe Fehlerbehandlung).
Für Felder reserviert Go eine bestimmte Menge an zusammenhängenden Speicher,
damit man effizient auf die einzelnen Werte zugreifen kann. Jedes Slice hat
eine Länge und eine Kapazität. Die Länge bestimmt das, was der Anwender sieht
(also die Felder, auf die man zugreifen kann) und die Kapazität die Menge der
Einträge, die man mit append()
hinzufügen kann, bevor Go
neuen Speicher reservieren muss.
package main
import "fmt"
func main() {
feld := make([]byte, 50, 100)
fmt.Println("Länge:", len(feld))
fmt.Println("Kapazität:", cap(feld))
feld[49] = 100
// geht nicht, da feld nur eine Länge von 50
// hat und die Indices von 0-49 gehen
// feld[50] = 100
feld = append(feld, 100)
fmt.Println(feld[50])
fmt.Println("Länge nach append:", len(feld))
fmt.Println("Kapazität nach append:", cap(feld))
}
Die Ausgabe ist:
$ go run main.go
Länge: 50
Kapazität: 100
100
Länge nach append: 51
Kapazität nach append: 100
fügt man noch weitere Einträge mit append()
hinzu, erhöht sich die Kapazität
des Slices entsprechend. Beachte aber, dass das Erweitern der Kapazität »teuer« ist.
Es muss neuer Speicher reserviert werde, und alle Einträge aus dem aktuellen Slice müssen in den neuen Speicher kopiert werden.
Bei zeitkritischen Routinen sollten man also ein wenig planen.