Pourquoi &str Ne Rentre Pas dans &String en Rust: Fixes Sympas pour les String Mismatches !
Table des matières
En Rust, tu ne peux pas passer un &str directement à une fonction attendant un &String à cause de leurs types distincts, ce qui assure la type safety et prévient les assumptions sur l'ownership mémoire. Ci-dessous, j'explique pourquoi ce mismatch survient et comment le gérer efficacement.
Le Problème Central : Type Mismatch
&String: Une référence vers unStringheap-allocated, extensible.&str: Une string slice qui peut pointer vers mémoire heap, stack, ou static.- Ce sont des types différents, donc Rust rejette les conversions implicites pour la sécurité.
Exemple : Le Problème :
fn print_string(s: &String) {
println!("{}", s);
}
fn main() {
let my_str = "hello"; // Type: `&'static str`
print_string(my_str); // ERREUR: expected `&String`, found `&str`
}
Solutions pour Relier &str et &String
1. Deref Coercion (Conversion Automatique)
Rust convertit automatiquement &String vers &str via le trait Deref, mais pas l'inverse. Le meilleur fix est de changer la fonction pour accepter &str pour plus de flexibilité.
fn print_str(s: &str) { // Maintenant accepte `&str` et `&String`
println!("{}", s);
}
fn main() {
let my_string = String::from("hello");
let my_str = "world";
print_str(&my_string); // Fonctionne: `&String` coerce vers `&str`
print_str(my_str); // Fonctionne directement
}
Pourquoi ça marche : String implémente Deref<Target=str>, permettant à &String de coercer vers &str.
2. Conversion Explicite (Quand Tu As Besoin de &String)
Si la fonction doit prendre &String, convertis &str vers String d'abord :
fn print_string(s: &String) {
println!("{}", s);
}
fn main() {
let my_str = "hello";
print_string(&my_str.to_string()); // Alloue un nouveau `String`
}
Inconvénient : Ceci alloue un nouveau buffer heap, ce qui devrait être évité si possible à cause des coûts de performance.
3. Utilise AsRef<str> pour Flexibilité Maximum
Pour des fonctions qui devraient marcher avec tout type string-like :
fn print_as_str<S: AsRef<str>>(s: S) {
println!("{}", s.as_ref());
}
fn main() {
let my_string = String::from("hello");
let my_str = "world";
print_as_str(&my_string); // Fonctionne
print_as_str(my_str); // Fonctionne
}
Bonus : Accepte aussi Cow<str>, Box<str>, etc.
Points Clés
✅ Préféré : Utilise &str dans les arguments de fonction (flexible et zero-cost).
✅ Si coincé avec &String : Convertis &str vers String (alloue).
✅ Pour les APIs : Utilise AsRef<str> ou impl Deref<Target=str> pour compatibilité maximum.
Pourquoi Rust Applique Ceci :
- Prévient les allocations accidentelles ou assumptions sur l'ownership mémoire.
- Encourage des APIs efficaces, borrow-friendly.
Essaie Ceci : Que se passe-t-il si tu passes un String à print_str sans & ?
Réponse : Ça move l'ownership, causant une erreur de compilation puisque print_str attend une référence (&str), pas un String owned.