Geschichte der Frage: In Go sind Strings (string) ein grundlegender und häufig verwendeter Typ, der aktiv für den Datenaustausch, Logging, Parsing usw. eingesetzt wird. Der Unterschied in Go ist, dass Strings unveränderlich sind, aus einer unveränderlichen Sequenz von Bytes bestehen und Daten im UTF-8-Format enthalten können.
Problem: Die Arbeit mit Strings und Byte-Slices ([]byte) wird oft verwechselt, es treten Fehler beim Ändern von Strings, beim Zerschneiden nach Runen und beim Versuch auf, mehrbyte Zeichen (z. B. kyrillische Schrift, Emoji) zu arbeiten.
Lösung:
Ein String ist unveränderlich, man kann seine Elemente nicht direkt ändern — der Versuch, s[0] zu ändern, ist unzulässig. Der String wird in UTF-8 kodiert, das heißt, ein Zeichen (Runa) kann breiter als ein Byte sein. Die Arbeit mit []byte ist kostengünstiger, erfordert jedoch manuelle Kontrolle. Die Umwandlung zwischen string <-> []byte erzeugt immer eine Kopie.
Beispielcode:
s := "привет" fmt.Println(len(s)) // 12 Bytes (Kyrillisch: je 2 Bytes) fmt.Println(len([]rune(s))) // 6 Runen, so viele Buchstaben fmt.Println(string([]byte{228, 189, 160, 229, 165, 189})) // chinesische Schriftzeichen
Wichtige Besonderheiten:
1. Kann man ein einzelnes Zeichen eines Strings über den Index ändern (z. B. s[1] = 'a')?
Antwort: Nein. Strings sind unveränderlich, der Compiler wird einen Fehler ausgeben. Man muss ein neues Slice []rune oder []byte erstellen, ändern und dann zurück in einen String konvertieren.
2. Warum stimmt len(str) nicht immer mit der Anzahl der Zeichen im String überein?
Antwort: len(str) ist die Anzahl der Bytes, nicht der Runen (Zeichen). Bei Kyrillisch oder Emoji kann eine lange Zeichenfolge einen intuitiv unerwarteten Wert zurückgeben. Für die Anzahl der Zeichen verwenden Sie []rune:
s := "мир 😀" fmt.Println(len(s)) // 7 fmt.Println(len([]rune(s))) // 5
3. Wird ein String per Referenz oder per Wert an eine Funktion übergeben?
Antwort: Per Wert, aber physisch wird ein Zeiger auf den Speicher und die Länge gespeichert. Nach der Übergabe "zeigen" zwei Variablen auf denselben Text, eine Kopie wird nicht automatisch erstellt. Eine tatsächliche Kopie des Speichers tritt bei der Umwandlung in []byte oder von []byte in string auf.
Ein Entwickler hat einen String mit russischen Zeichen, nimmt die ersten 4 Bytes und erwartet den ersten Buchstaben zu erhalten, aber es kommt nur die halbe Zeichen — es entstehen "beschädigte" Zeichen.
Vorteile: Es ging schnell und kurz. Nachteile: Falsche Arbeit mit Unicode-Daten, "beschädigte" Strings, Panik beim Versuch, solche Strings an anderen Stellen zu parsen.
Strings werden in []rune umgewandelt, um mit Zeichen zu arbeiten, nach den erforderlichen Aktionen wird der String wieder durch string() zusammengesetzt. Die Arbeit mit []byte erfolgt nur für niedrigebene Serialisierung, unter Berücksichtigung der Kodierung.
Vorteile: Korrekte Verarbeitung von Unicode, Zuverlässigkeit der Funktionen. Nachteile: Etwas langsamer, benötigt mehr Speicher, ist aber sicher für beliebige Strings.