So konvertieren Sie einen String in einen & 'statischen Str

89

Wie wandle ich ein Stringin ein um &str? Genauer gesagt möchte ich es in ein strmit der staticLebensdauer ( &'static str) umwandeln .

Christoph
quelle
Das scheint weder möglich noch wünschenswert. 'staticDie Lebensdauer würde bedeuten, dass die Zeichenfolge niemals freigegeben wird, dh ein Speicherverlust. Warum brauchst du &'static strstatt &'a strfür ein passendes 'a?
3
Wie würde es aussehen, es &'a str dann umzuwandeln ?
Christoph
Via as_slice. Es wäre einfacher zu helfen, wenn Sie beschreiben würden, welches konkrete Problem Sie lösen möchten und auf welche Probleme Sie dabei stoßen.
Beachten Sie SendStrauch einen Typ, der entweder eine eigene Zeichenfolge oder eine statische Zeichenfolge ist.
Chris Morgan

Antworten:

132

Aktualisiert für Rust 1.0

Sie können nicht &'static strvon a erhalten, Stringweil Strings möglicherweise nicht für das gesamte Leben Ihres Programms lebt, und das ist, was &'staticLeben bedeutet. Sie können nur ein Slice erhalten, das nach seiner Stringeigenen Lebensdauer parametrisiert ist.

Um von einem Stringzu einem Slice zu wechseln &'a str, können Sie die Slicing-Syntax verwenden:

let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..];  // take a full slice of the string

Alternativ können Sie die Tatsache verwenden, dass eine explizite Neuausleihe Stringimplementiert Deref<Target=str>und durchgeführt wird:

let s_slice: &str = &*s;  // s  : String 
                          // *s : str (via Deref<Target=str>)
                          // &*s: &str

Es gibt noch einen anderen Weg, der eine noch präzisere Syntax ermöglicht, der jedoch nur verwendet werden kann, wenn der Compiler den gewünschten Zieltyp bestimmen kann (z. B. in Funktionsargumenten oder explizit typisierten Variablenbindungen). Es wird als Deref-Zwang bezeichnet und ermöglicht die Verwendung eines einfachen &Operators. Der Compiler fügt automatisch eine geeignete Menge von *s ein, basierend auf dem Kontext:

let s_slice: &str = &s;  // okay

fn take_name(name: &str) { ... }
take_name(&s);           // okay as well

let not_correct = &s;    // this will give &String, not &str,
                         // because the compiler does not know
                         // that you want a &str

Beachten Sie, dass dieses Muster nicht eindeutig für String/ ist. &strSie können es für jedes Typenpaar verwenden, das Derefbeispielsweise mit CString/ CStrund OsString/ OsStrvom std::ffiModul oder PathBuf/ Pathvom std::pathModul verbunden ist.

Vladimir Matveev
quelle
26
In Rust 1.10 können Sie stattdessen let s_slice: &str = &s[..];einfach let s_slice: &str = s.as_str();
Folgendes
3
Manchmal lebt die ursprüngliche Zeichenfolge nicht genug, wie in einem Match-Block. Das wird zu einem führen 's' does not live long enough error.
Dereckson
37

Sie können es tun, aber es geht darum , die Erinnerung an die zu verlierenString . Dies sollten Sie nicht leichtfertig tun. Durch das Lecken des Speichers von Stringgarantieren wir, dass der Speicher niemals freigegeben wird (also das Leck). Daher können alle Verweise auf das innere Objekt so interpretiert werden, dass sie die 'staticLebensdauer haben.

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let s: &'static str = string_to_static_str(s);
}
oli_obk
quelle
7
Stringgarantiert, dass der Speicher am Leben bleibt, solange das Objekt nicht gelöscht wurde. Da mem::forgetgarantiert wird, dass das Objekt niemals gelöscht wird, ist garantiert, dass der Verweis auf das Enthaltene strniemals ungültig wird. Somit können wir behaupten, dass es sich um eine 'staticReferenz handelt
oli_obk
1
Dies war unglaublich hilfreich für meine Rust-Anwendung, die eine Stringin eine zwingen musste, &'static strdamit aus dem Original erstellte Token für Stringalle Threads verfügbar waren. Ohne dies würde sich der Rust-Compiler beschweren, dass mein StringLeben am Ende der Hauptfunktion endete, was nicht gut genug war, weil es keine 'staticGarantie gab.
mmstick
1
@mmstick: Die bessere Lösung in diesem Fall wäre die Verwendung crossbeamvon Threads mit
Gültigkeitsbereich
3
@mmstick: Wenn Sie Ihre gesamte Anwendung in einen Crossbeam-Bereich einfügen und die Zeichenfolge außerhalb des Bereichs erstellen, erhalten Sie genau das.
oli_obk
1
Diese Antwort ist großartig! Beide sagten mir, wie man ein statisches String-Slice erstellt, und überzeugten mich, es nicht zu tun! Ich habe mich entschieden, meine App so umzugestalten, dass an so vielen Stellen keine statischen String-Slices verwendet werden.
Paul Chernoch
21

Ab Rust Version 1.26 ist es möglich , eine konvertieren Stringzu , &'static strohne den unsafeCode ein :

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

Dies konvertiert die StringInstanz in eine Box strund leckt sie sofort. Dadurch wird die gesamte überschüssige Kapazität freigegeben, die der String derzeit möglicherweise belegt.

Beachten Sie, dass es fast immer Lösungen gibt, die gegenüber undichten Objekten vorzuziehen sind, z. B. die Verwendung der crossbeamKiste, wenn Sie den Status zwischen Threads teilen möchten.

Sven Marnach
quelle
2

TL; DR: Sie können eine &'static strvon einer bekommen, Stringdie selbst ein 'staticLeben lang hat.

Obwohl die anderen Antworten korrekt und am nützlichsten sind, gibt es einen (nicht so nützlichen) Randfall, in dem Sie tatsächlich a Stringin a konvertieren können &'static str:

Die Lebensdauer einer Referenz muss immer kürzer oder gleich der Lebensdauer des referenzierten Objekts sein. Das heißt, das referenzierte Objekt muss länger (oder gleich lange) leben als die Referenz. Da 'staticdies die gesamte Lebensdauer eines Programms bedeutet, gibt es keine längere Lebensdauer. Eine gleiche Lebensdauer wird jedoch ausreichen. Wenn a Stringalso eine Lebensdauer von hat 'static, können Sie eine &'static strReferenz daraus erhalten.

Das Erstellen eines staticTyps Stringist mit Rust 1.31 theoretisch möglich geworden, als die const fnFunktion veröffentlicht wurde. Leider ist die einzige konstante Funktion einer Rückkehr Stringist String::new()zur Zeit, und es ist immer noch hinter einem Feature - Gate (so Rust allabendlich für jetzt ist erforderlich).

Der folgende Code führt also die gewünschte Konvertierung durch (unter Verwendung von nächtlichen) ... und hat tatsächlich keine praktische Verwendung, außer der Vollständigkeit des Nachweises, dass dies in diesem Randfall möglich ist.

#![feature(const_string_new)]

static MY_STRING: String = String::new();

fn do_something(_: &'static str) {
    // ...
}

fn main() {
    do_something(&MY_STRING);
}
Zargony
quelle