„How do I convert between String, &str, Vec<u8> and &[u8]?“ — Ihre Checkliste zur Optimierung in Rust
\n\nWenn Sie jemals Rust-Code geschrieben haben, der mit Text oder Bytes arbeitet, sind Sie sicherlich auf die Frage gestoßen: „Wie konvertiere ich String in &str? Und Vec<u8> in &[u8]? Und umgekehrt?“. Dies ist eine der häufigsten Fragen auf Stack Overflow (Zehntausende von Aufrufen), und das aus gutem Grund. Die scheinbar einfachen Konvertierungen bergen Fallstricke, insbesondere wenn es um die Leistung geht.
In diesem Artikel listen wir nicht nur die Methoden „wie es geht“ auf. Wir analysieren, warum einige Methoden schneller sind als andere und wann Sie welche verwenden sollten. Sie erfahren, wie Sie unnötige Kopiervorgänge, überflüssige Allokationen vermeiden und wirklich effizienten Code in Rust schreiben.
\n\nWarum ist das wichtig? Kontext und Leistung
\nRust ist eine Sprache, die Ihnen die Kontrolle über den Speicher gibt. Aber mit der Kontrolle kommt Verantwortung. Die Konvertierung zwischen Strings und Bytes ist eine der häufigsten Operationen. Zum Beispiel bei der Arbeit mit Netzwerkprotokollen, Datenserialisierung (JSON, Protobuf) oder einfach beim Lesen von Dateien. Eine falsche Wahl der Konvertierung kann dazu führen, dass Sie Daten kopieren, die Sie ohne Kopieren hätten nutzen können. In der Welt der Systemprogrammierung ist das kritisch.
\n\nLassen Sie uns die vier grundlegenden Typen analysieren und lernen, wie wir verlustfrei zwischen ihnen wechseln können.
\n\nString und &str: Zwei Seiten derselben Medaille
\nString ist ein besitzender, veränderlicher UTF-8-String. &str ist ein geliehener, unveränderlicher Slice eines Strings. Die Hauptregel: String ist der Eigentümer der Daten, &str ist ein Verweis auf die Daten.
Wie erhalte ich &str aus String (und umgekehrt)
\nDies ist der einfachste und sicherste Fall.
\n\nlet my_string = String::from("Hallo, Welt!");\n// 1. &str aus String erhalten (einfach ausleihen)\nlet my_str: &str = &my_string;\n// Oder mit as_str()\nlet my_str2: &str = my_string.as_str();\n\n// 2. String aus &str erhalten (eine neue Kopie erstellen)\nlet new_string: String = my_str.to_string();\n// Oder\nlet new_string2: String = String::from(my_str);\n\nWichtig: Die Konvertierung von &str in String erzeugt immer neuen allozierten Speicher (eine Allokation). Das ist teuer. Die Konvertierung von String in &str ist lediglich das Nehmen einer Referenz (kostenlos).
Wie erhalte ich Vec<u8> aus String (und umgekehrt)
\nHier wird es interessant, denn String ist intern einfach ein Vec<u8> mit der Garantie korrekten UTF-8.
let my_string = String::from("Rust");\n\n// 3. String -> Vec<u8>\n// Variante A (Kopieren): sicher, aber teuer\nlet bytes_vec_copy: Vec<u8> = my_string.as_bytes().to_vec();\n\n// Variante B (ohne Kopieren, Konsumieren des String):\nlet bytes_vec_owned: Vec<u8> = my_string.into_bytes(); // my_string existiert nicht mehr!\n\n// 4. Vec<u8> -> String (Prüfung auf korrektes UTF-8)\nlet new_string: String = String::from_utf8(bytes_vec_owned).expect("Ungültiges UTF-8");\n// Wenn Sie sich der Gültigkeit sicher sind:\nlet new_string_unchecked: String = unsafe { String::from_utf8_unchecked(bytes_vec_copy) };\n\nKernpunkt: into_bytes() ist eine zero-cost-Konvertierung. Es nimmt den internen Vec<u8>-Puffer und gibt ihn an Sie weiter, ohne ein einziges Byte zu kopieren. as_bytes().to_vec() ist eine explizite Kopie.
Die Methode from_utf8_unchecked ist unsafe. Verwenden Sie sie nur, wenn Sie zu 100% sicher sind, dass die Bytes gültiges UTF-8 sind. Andernfalls kann das Programm mit einer Panik oder, schlimmer noch, mit UB (undefined behavior) abstürzen.