Zeichenketten (strings) und Zeichen (rune)

Ein grundlegender Datentyp wurde in der Einleitung schon dargestellt: string, auf Deutsch in etwa Zeichenkette. Dieser Datentyp speichert vor allem Texte, kann aber beliebige Inhalte speichern (Binärdaten). Ein string ist eine Aneinanderreihung von Bytes, deren Bedeutung je nach Anwendungsfall unterschiedlich ist. Meist spricht man von Zeichenketten, wenn lesbare Texte gespeichert sind. Ansonsten nennt man sie »Binärdaten« oder einfach nur »Daten«. Beispiele für Zeichenketten sind "Hallo" oder "132". Zeichenketten werden meist in doppelten Anführungszeichen (", »Gänsefüßchen«) geschrieben, sie können aber auch in Backticks geklammert werden: `Hallo Welt`. Zeichenketten in doppelten Anführungszeichen müssen in einer Zeile stehen:

// erlaubt:
a := `Hallo
      Welt`
// nicht erlaubt
b := "Hallo
      Welt"

Zeichenketten in doppelten Anführungszeichen dürfen beliebige Bytewerte enthalten, die mit einem Schrägstrich markiert werden. Beispielsweise:

  • \123 als für eine Zahl zur Basis 8 (Oktalzahl).
  • In der Form \x0F für Zahlen zur Basis 16 (Hexadezimalzahlen).
  • \n (oder einen der Buchstaben a, b, f, r, t oder v) für die Bytewerte 10, 7, 8, 12, 13, 9 und 11.
  • \u00f6 als Unicode-Codepoint, der in eine UTF-8 Bytefolge umgewandelt wird.
  • \" für das Anführungszeichen, das in dem Fall nicht als Ende der Zeichenkette interpretiert wird.

Eine Zeichenkette ist nicht veränderbar. Man kann nicht ein Zeichen in einer bestehenden Zeichenkette verändern, jedoch lesen:

package main

import "fmt"

func main() {
    gruß := "Hallo"
    // schreibt den Wert des dritten Elements
    fmt.Println(gruß[2])
    // geht nicht, der string ist unveränderbar

    // Fehler ist: `cannot assign to gruß[2]'
    gruß[2] = 'x'
}

Die Länge einer Zeichenkette ist über die eingebaute Funkton len() ermittelbar: len(gruß) im Beispiel ergibt 5. Das entspricht aber nicht immer der Anzahl der enthaltenen Zeichen, da manche Zeichen (wie zum Beispiel Umlaute) aus mehreren Bytes bestehen. Die Länge der Zeichenkette "schön" über len() ermittelt ergibt 6.

Da Computer nur die Zahlen 0-255 (1 Byte) verarbeiten können und eigentlich keine Kenntnis über Zeichen haben, benötigt man eine genormte Zuordnung von Zeichen zu Zahlenwerten, eine sogenannte Kodierung. Bis vor wenigen Jahren herrschte ein ziemliches Durcheinander wenn es darum ging, »Sonderzeichen« wie Umlaute, Akzente auch das Paragraphenzeichen (§) einer Zahl zuzuordnen. Inzwischen hat sich die Zuordnung »Unicode« etabliert, die das Problem für alle bekannten Zeichen löst. Da es aber sehr viel mehr Zeichen gibt, als Computer in einem Byte speichern können (Werte bis 255), benötigt man noch ein Verfahren die großen Zahlen auf Bytes aufzuteilen. Das gängigste Verfahren heißt UTF-8 und wird bei Go im Quelltext benutzt. Achte also darauf, Quelltexte immer als UTF-8 kodierte Dateien speichern.

Zeichenketten können nicht nur (verlustlos) in ein Byte-Slice umgewandelt werden, sondern auch in ein rune-Slice. Rune ist ein eingebauter Datentyp, der alle darstellbaren Zeichen speichern kann (Unicode)[1]. Um eine Zeichenkette in rune-Werte zu wandeln, muss sie in UTF-8 kodiert sein. Mithilfe der for-range-Schleife teilt man eine Zeichenkette in die einzelnen Zeichen auf:

package main

import "fmt"

func main() {
    for i, r := range "ħałłø" {
        fmt.Println(i, r)
    }
}

Ausgabe:

0 295
2 97
3 322
5 322
7 248

Die Ausgabe ist in sofern interessant, weil die erste Zahl (i) die Position des ersten Bytes des UTF-8 kodierten Zeichens (r) angibt. Es gibt viele Funktionen in der Standardbibliothek von Go, die auf den Datentypen string und rune arbeiten.


1. Strenggenommen ist rune nur ein Alias für int32.