Historique de la question
En Rust, on distingue deux types de chaînes principaux : &str (slice de chaîne, immuable, souvent littéral de chaîne) et String (chaîne dynamique, mutable). Aux premières étapes de développement du langage, le choix entre eux a permis de simplifier la gestion efficace de la mémoire et de garantir la sécurité des types lors du traitement des données textuelles grâce à un système strict de possession et de références.
Problème
De nombreux développeurs se perdent lors de l'interaction entre ces types. Par exemple, un littéral de chaîne est un &'static str, c'est-à-dire une référence à une chaîne immuable allouée au moment de la compilation, tandis que String peut s'étendre dynamiquement et contenir des données obtenues à l'exécution. Des questions se posent sur la manière de convertir entre les types, d'utiliser correctement la possession et d'éviter des copies inutiles.
Solution
La conversion entre &str et String est transparente si l'on comprend les règles de possession de base :
String via une référence (my_string.as_str()) ou un simple emprunt (&my_string).&str en String en utilisant to_string() ou String::from().Exemple de code :
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); }
Caractéristiques clés :
&str n'occupe pas de mémoire sur le tas, toujours immuable.String alloue de la mémoire dynamiquement, peut être modifiée.Peut-on modifier un littéral de chaîne en Rust ?
Non, un littéral de chaîne (&'static str) est toujours immuable, toute tentative de modification d'un caractère entraînera une erreur à la compilation.
Est-il suffisant d'appeler .to_string() sur &str pour obtenir une chaîne mutable sans copies inutiles ?
Non, .to_string() alloue toujours une nouvelle mémoire et copie le contenu. C'est inévitable si une chaîne mutable est nécessaire à partir d'un slice.
Peut-on obtenir une référence &str à partir de String sans risque de fuite de durée de vie ?
Oui, une référence obtenue de cette manière (let s: &str = &my_string;) ne vit pas plus longtemps que le String d'origine. Essayer de retourner &str d'un String local dans une fonction entraînera une erreur de durée de vie.
&str vers un String temporaire qui sort de la portée&str en String sans nécessité (allocations inutiles)String::from("text") ne crée pas de copie des donnéesLa fonction retourne &str, qui fait référence à un String temporaire à l'intérieur de la fonction :
fn faulty() -> &str { let s = String::from("Oops"); &s // erreur de durée de vie ! }
Avantages :
Inconvénients :
La fonction retourne directement un String et passe la possession à l'appelant :
fn correct() -> String { String::from("Safe!") }
Avantages :
Inconvénients :