ProgrammierungFullstack Entwickler

Wie funktioniert die Arbeit mit unveränderlichen Zeichenfolgen und dem dynamischen Typ String in Rust? Was sind die Unterschiede zwischen String und &str, wie funktioniert das Ownership und wie kann man sicher zwischen diesen Typen konvertieren?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Geschichte der Frage:

Im Vergleich zu nativen Sprachen (C/C++) ermöglicht Rust eine sichere Arbeit mit Zeichenfolgen durch eine strikte Trennung zwischen referenzierten (&str) und besitzenden (String) Typen. Dies beseitigt die meisten Fehler, die mit falschem Speicher, Pufferüberlauf und Double-Free verbunden sind.

Problem:

Im Gegensatz zu "großen" GC-Sprachen, in denen jede Zeichenfolge im verwalteten Speicher lebt, muss man in Rust genau verstehen, wer die Zeichenfolge besitzt, wie lange sie lebt und wie man keine dangling references nach Modifikationen erhält. Die Arbeit mit UTF-8-Zeichenfolgen erfordert Vorsicht beim Indizieren und Ändern.

Lösung:

In Rust ist String eine veränderbare, heap-allokierte Zeichenfolge, die ihren Inhalt besitzt. &str ist ein unveränderlicher Verweis auf eine Folge von Bytes mit der Garantie UTF-8. Bei Bedarf kann man sicher konvertieren (&str -> String und zurück) mit Hilfe von Methoden aus der Standardbibliothek.

Beispielcode:

fn main() { let owned: String = String::from("Rust"); let borrowed: &str = &owned; let primitive: &str = "Hello"; // Literale sind immer &str // Konvertierung von &str -> String let s: String = primitive.to_string(); // Konvertierung von String -> &str let st: &str = &s; println!("{} {} {} {}", owned, borrowed, primitive, st); }

Schlüsselmerkmale:

  • Eindeutige Trennung zwischen Besitz und Referenz (heap vs slice)
  • Methoden für sichere Konversionen zwischen String und &str sind effizient und transparent hinsichtlich der Lebensdauer des Objekts
  • Zeichenfolgenliterale haben immer den Typ &'static str und nicht String

Fangfragen.

Warum kann man eine Zeichenfolge nicht wie s[1] oder s[i] indizieren?

Rust verwendet UTF-8 für Zeichenfolgen, daher ist die Indizierung nicht direkt verfügbar: s[i] gibt nicht das i-te Zeichen zurück und kann manchmal zu einem Panic führen, wenn man außerhalb der Grenzen von Bytes zugreift. Stattdessen sollten Sie die Methoden .chars().nth(i) oder .get(start..end) verwenden.

Kann man &str sicher modifizieren?

Nein - &str ist immer ein unveränderliches Slice. Für Modifikationen verwenden Sie to_owned/to_string oder nutzen Sie String/Vec<u8>.

Was ist der wesentliche Unterschied zwischen String::from("abc") und "abc".to_string()?

Diese Varianten sind in Bezug auf das Ergebnis äquivalent, beide erstellen eine String durch Kopieren von Daten aus &str. Der Unterschied liegt nur im Stil: zum Beispiel, to_string ist über das Trait ToString implementiert, während String::from klarer den Intent ausdrückt, "Besitz zu schaffen".

Typische Fehler und Anti-Patterns

  • Versuch, die Zeichenfolge s[1] oder s[0] zur Gewinnung von char zu indizieren
  • Implizite Konversionen ohne Angabe der Lebensdauer: Rückgabe von Referenzen auf temporäre Objekte
  • Verwendung von String, wo &str ausreichend ist (überflüssige Allokation)

Beispiel aus dem Leben

Negativer Fall

Die Funktion nahm eine String entgegen und führte eine unnötige Kopie der Zeichenfolge innerhalb durch (clone), schrieb dann ein Slice in eine andere Funktion, ohne die Lebensdauer der Quelle zu verlängern. Ergebnis: dangling reference & Absturz.

Vorteile:

  • Ähnlich wie in gewohnten Sprachen: Man kann leicht eine "Kopie" der Zeichenfolge erhalten.

Nachteile:

  • Leistungseinbußen durch überflüssige Allokationen
  • Möglicher Leck von Referenzen auf temporäre Werte

Positiver Fall

Die Funktion akzeptiert &str, wenn Modifikationen benötigt werden - innerhalb wird .to_string() aufgerufen, während die gesamte Logik "zero copy" bleibt. Lebensdauern sind unter Kontrolle, keine überflüssige Allokation.

Vorteile:

  • Hohe Leistung
  • Fehler beim Besitz wurden vermieden

Nachteile:

  • Man muss sich mit Lebensdauern und Besitz auseinandersetzen
  • Etwas mehr kognitive Belastung für Anfänger