Hintergrund
In Rust werden zwei grundlegende String-Typen unterschieden — &str (String-Slice, unveränderlich, häufig ein String-Literal) und String (dynamisch, veränderlicher String). In den frühen Entwicklungsphasen der Sprache hat die Wahl zwischen ihnen dazu beigetragen, die Arbeit mit effizientem Speicher zu vereinfachen und die Typsicherheit bei der Verarbeitung von Textdaten durch ein strenges Besitz- und Referenzsystem zu gewährleisten.
Problem
Viele Entwickler sind bei der Interaktion zwischen diesen Typen verwirrt. Zum Beispiel ist ein String-Literal ein &'static str, also ein Verweis auf einen unveränderlichen String, der zur Kompilierungszeit zugewiesen wird, während String dynamisch erweitert werden kann und Daten enthält, die zur Laufzeit erhalten werden. Es kommen Fragen auf, wie man zwischen den Typen konvertiert, den Besitz richtig verwendet und unnötige Kopien vermeidet.
Lösung
Die Konvertierung zwischen &str und String ist einfach, wenn man die grundlegenden Regeln des Besitzes versteht:
String über eine Referenz (my_string.as_str()) oder einfache Entlehnung (&my_string) erhalten.&str in String mit to_string() oder String::from() umwandeln.Beispielcode:
fn main() { let s_literal: &str = "hello"; let s_string: String = String::from(s_literal); let s_slice: &str = &s_string; let new_string = s_slice.to_string(); println!("{} {}", s_string, new_string); }
Wichtige Merkmale:
&str belegt keinen Heap-Speicher, immer unveränderlich.String belegt dynamisch Speicher, veränderbar.Kann man ein String-Literal in Rust ändern?
Nein, ein String-Literal (&'static str) ist immer unveränderlich, jeder Versuch, ein Zeichen zu ändern, führt zu einem Kompilierungsfehler.
Reicht es aus, .to_string() auf &str aufzurufen, um einen veränderbaren String ohne unnötige Kopien zu erhalten?
Nein, .to_string() allokiert immer neuen Speicher und kopiert den Inhalt. Das ist unvermeidlich, wenn ein veränderbarer String auf der Grundlage eines Slices benötigt wird.
Kann man eine Referenz &str aus String ohne Risiko eines Lebenszeit-Lecks erhalten?
Ja, die auf diese Weise erhaltene Referenz (let s: &str = &my_string;) lebt nicht länger als der ursprüngliche String. Der Versuch, &str von einem lokalen String aus einer Funktion zurückzugeben, führt zu einem Lebenszeitfehler.
&str auf einen temporären String speichern, der außerhalb des Gültigkeitsbereichs ausgeht.&str in String umwandeln, ohne dass es notwendig ist (überflüssige Allokationen).String::from("text") keine Kopie der Daten erstellt.Eine Funktion gibt &str zurück, das auf einen temporären String innerhalb der Funktion verweist:
fn faulty() -> &str { let s = String::from("Oops"); &s // Lebenszeitfehler! }
Vorteile:
Nachteile:
Eine Funktion gibt sofort einen String zurück und überträgt das Eigentum an den Aufrufer:
fn correct() -> String { String::from("Safe!") }
Vorteile:
Nachteile: