web-dev-qa-db-fra.com

Comment convertir une chaîne en & str statique

Comment convertir une String en un &str? Plus précisément, je voudrais le convertir en une str avec la vie static (&'static str).

52
Christoph

Mis à jour pour Rust 1.0

Vous ne pouvez pas obtenir &'static str à partir d'une String car Strings ne dure pas toute la vie de votre programme, et c'est ce que &'static durée de vie signifie. Vous ne pouvez obtenir qu'une tranche paramétrée par String propre durée de vie à partir de celle-ci.

Pour passer d'une String à une tranche &'a str, vous pouvez utiliser la syntaxe de découpage:

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

Sinon, vous pouvez utiliser le fait que String implémente Deref<Target=str> et effectue un reborrowing explicite:

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

Il existe même une autre méthode permettant une syntaxe encore plus concise, mais elle ne peut être utilisée que si le compilateur est capable de déterminer le type de cible souhaité (par exemple, dans des arguments de fonction ou des liaisons de variables explicitement typées). Il s’appelle deref coercion et permet d’utiliser uniquement l’opérateur &. Le compilateur insère automatiquement une quantité appropriée de *s en fonction du contexte:

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

Notez que ce modèle n'est pas unique pour String/&str - vous pouvez l'utiliser avec chaque paire de types connectés via Deref, par exemple, avec CString/CStr et OsString/OsStrde std::ffi module ou PathBuf/Pathstd::path module.

81
Vladimir Matveev

Vous pouvez le faire, mais cela implique une fuite de la mémoire de String. Ce n'est pas quelque chose que vous devriez faire à la légère. En fuyant la mémoire de la variable String, nous garantissons que la mémoire ne sera jamais libérée (donc la fuite). Par conséquent, toute référence à l'objet interne peut être interprétée comme ayant la durée de vie 'static.

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);
}
16
oli_obk

À partir de Rust version 1.26, il est possible de convertir une String en &'static str sans utiliser le code unsafe:

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

Cela convertit l'instance String en une str encadrée et la perd immédiatement. Cela libère toute la capacité excédentaire actuellement occupée par la chaîne.

Notez qu'il existe presque toujours des solutions préférables aux objets présentant des fuites, par ex. utilisez la caisse crossbeam si vous souhaitez partager l’état entre les threads.

10
Sven Marnach

TL; DR: vous pouvez obtenir un &'static str à partir d'une String qui a elle-même une durée de vie 'static.

Bien que les autres réponses soient correctes et très utiles, il existe un cas Edge (pas très utile), dans lequel vous pouvez en effet convertir une String en &'static str:

La durée de vie d'une référence doit toujours être inférieure ou égale à la durée de vie de l'objet référencé. C'est à dire. l'objet référencé doit vivre plus longtemps (ou plus longtemps que la référence). Puisque 'static correspond à la durée de vie complète d’un programme, il n’existe pas de durée de vie plus longue. Mais une durée de vie égale sera suffisante. Donc, si une String a une durée de vie de 'static, vous pouvez en obtenir une référence &'static str.

La création d'une static de type String est devenue théoriquement possible avec Rust 1.31 lorsque la fonctionnalité const fn a été publiée. Malheureusement, la seule fonction const retournant une String est String::new() pour le moment et elle est toujours derrière une porte de fonctionnalité (donc Rust nightly est requis pour l'instant).

Ainsi, le code suivant effectue la conversion souhaitée (en utilisant nocturne) ... et n'a en fait aucune utilisation pratique, si ce n'est qu'il est complet de montrer que cela est possible dans ce cas Edge.

#![feature(const_string_new)]

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

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

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