Warum sind Sie hier? Seien Sie ehrlich
\n\nSie programmieren in Rust und stoßen plötzlich auf eine Wand. Sie haben ein Option<String> – einen Wert, der vorhanden sein kann oder auch nicht. Aber die Funktion, die Sie aufrufen möchten, erwartet Option<&str>. Und der Compiler blickt Sie vorwurfsvoll an und gibt einen Fehler aus, bei dem Sie am liebsten den Laptop zuklappen und Tee trinken gehen würden.
Keine Sorge. Diese Situation tritt so häufig auf, dass die Frage "Converting from Option<String> to Option<&str>" auf Stack Overflow tausende Aufrufe gesammelt hat. Sie sind nicht allein.
\n\nIn diesem Artikel werden wir verstehen, warum diese Konvertierung so viele Fragen aufwirft, und – am wichtigsten – wie man sie richtig durchführt. Ohne Magie, ohne unnötiges Kopieren im Speicher, mit vollständigem Verständnis dessen, was unter der Haube passiert.
\n\nDas Problem: Warum kann man nicht einfach konvertieren?
\n\nZunächst ein kurzer Blick auf die Typen.
\n\n- \n
Stringist ein besitzender Typ. Er besitzt die Daten auf dem Heap und ist für deren Freigabe verantwortlich. \n &strist ein Verweis auf einen String-Slice. Er leiht sich die Daten aus, ohne sie zu besitzen. \n
Und hier beginnt der Spaß. Option<String> ist ein möglicherweise vorhandener String, den Sie besitzen. Option<&str> ist ein möglicherweise vorhandener Verweis auf einen String.
Das Problem ist, dass Sie nicht einfach einen Verweis auf den Wert innerhalb des Option nehmen und nach außen geben können, wenn das Option temporär ist. Der Verweis muss auf etwas zeigen, und dieses "Etwas" muss lange genug leben.
Schauen wir uns einen typischen Anfängerfehler an:
\n\nfn process(value: Option<String>) {\n // Fehler! cannot return reference to temporary value\n let ref_value: Option<&str> = value.as_ref().map(|s| s.as_str());\n // oder noch direkter:\n let ref_value: Option<&str> = Some(value.unwrap().as_str()); // BUMM!\n}\n\nDer Compiler explodiert in Rot. Warum? Weil value der Besitzer des Strings ist. Wenn Sie versuchen, einen &str davon zu nehmen, darf der Verweis nicht länger leben als value selbst. Und wenn value ein temporäres Objekt ist (z. B. das Ergebnis eines Funktionsaufrufs), wird der Verweis zu einem hängenden Verweis (dangling reference).
Lösung Nr. 1: as_deref() – Ihr neuer bester Freund
\n\nDer eleganteste Weg, Option<String> in Option<&str> zu konvertieren, ist die Methode as_deref().
Wie funktioniert das? as_deref() macht zwei Dinge:
- \n
- Es nimmt
&Option<T>und wandelt es inOption<&T>um (das machtas_ref()). \n - Dann wendet es
Derefauf den inneren Wert an und wandelt&Stringin&strum. \n
So sieht das im Code aus:
\n\nfn main() {\n let my_string: Option<String> = Some(String::from("Hallo, Rust!"));\n \n // Magie in einer Zeile:\n let my_str_ref: Option<&str> = my_string.as_deref();\n \n match my_str_ref {\n Some(s) => println!("String: {}", s),\n None => println!("Kein String vorhanden"),\n }\n // my_string lebt und ist wohlauf!\n println!("Ursprünglicher String: {:?}", my_string);\n}\n\nBeachten Sie: my_string bleibt der Besitzer der Daten. Wir haben nur einen Verweis auf seinen Inhalt genommen. Das bedeutet, dass my_str_ref nur so lange lebt, wie my_string lebt.
Was ist, wenn Option leer ist?
\nGanz einfach:
\n\nfn main() {\n let empty: Option<String> = None;\n let result: Option<&str> = empty.as_deref();\n println!("{:?}", result); // None\n}\n\nKeine Paniken, keine Abstürze. Funktioniert wie ein Uhrwerk.