Top des erreurs des développeurs Rust débutants : de A à Z
\n\nRust est un langage de programmation puissant et sûr, mais son système strict de possession et d'emprunt déroute souvent les débutants. Dans cet article, nous analyserons les erreurs les plus courantes rencontrées par les développeurs débutants en Rust. Chaque erreur est accompagnée d'un exemple de code, d'une explication et de la solution correcte. C'est parti !
\n\n1. Ignorer le système de possession (Ownership)
\n\nL'erreur la plus fréquente est de tenter d'utiliser une valeur après son déplacement. En Rust, chaque valeur ne peut avoir qu'un seul propriétaire.
\n\n❌ Code erroné :
\nfn main() {\n let s1 = String::from("bonjour");\n let s2 = s1;\n println!("{}", s1); // Erreur ! s1 ne possède plus la chaîne\n}\n\n\n✅ Solution correcte :
\nfn main() {\n let s1 = String::from("bonjour");\n let s2 = s1.clone(); // Copie explicite\n println!("{}", s1); // Fonctionne maintenant\n println!("{}", s2);\n}\n\n\nConseil : Utilisez .clone() uniquement lorsque c'est vraiment nécessaire. Pour les types primitifs (i32, bool), la copie se fait automatiquement.
2. Confusion entre String et &str
\n\nLes débutants ne comprennent souvent pas la différence entre la chaîne possédée String et la tranche de chaîne &str. Cela entraîne des erreurs lors du passage de chaînes aux fonctions.
❌ Code erroné :
\nfn print_message(msg: String) {\n println!("{}", msg);\n}\n\nfn main() {\n let greeting = "Bonjour"; // &str\n print_message(greeting); // Erreur ! String attendue\n}\n\n\n✅ Solution correcte :
\nfn print_message(msg: &str) {\n println!("{}", msg);\n}\n\nfn main() {\n let greeting = "Bonjour";\n print_message(greeting); // Fonctionne !\n \n let owned = String::from("Monde");\n print_message(&owned); // &String est automatiquement converti en &str\n}\n\n\nRègle d'or : Dans les paramètres de fonction, utilisez &str si vous n'avez pas besoin de transférer la possession de la chaîne.
3. Violation des règles d'emprunt (Borrowing)
\n\nRust ne permet pas d'avoir simultanément une référence mutable et une référence immuable sur le même objet. Cela protège contre les courses de données.
\n\n❌ Code erroné :
\nfn main() {\n let mut data = vec![1, 2, 3];\n let ref1 = &data;\n let ref2 = &mut data; // Erreur ! Il existe déjà une référence immuable\n println!("{}", ref1);\n}\n\n\n✅ Solution correcte :
\nfn main() {\n let mut data = vec![1, 2, 3];\n {\n let ref1 = &data;\n println!("{}", ref1); // ref1 ne vit que dans ce bloc\n } // ref1 sort de la portée\n let ref2 = &mut data; // Maintenant possible\n ref2.push(4);\n println!("{:?}", ref2);\n}\n\n\nImportant : La portée d'une référence se termine à sa dernière utilisation. Le compilateur Rust est suffisamment intelligent pour le détecter.
\n\n4. Problèmes avec les durées de vie (Lifetimes)
\n\nLes erreurs liées aux annotations de durée de vie effraient le plus les débutants. La plus typique est le retour d'une référence à une variable locale.
\n\n❌ Code erroné :
\nfn get_reference() -> &str {\n let local = String::from("test");\n &local // Erreur ! local sera détruite après la sortie de la fonction\n}\n\n\n✅ Solution correcte (via la possession) :
\nfn get_reference() -> String {\n let local = String::from("test");\n local // Retourne la possession\n}\n\nfn main() {\n let s = get_reference();\n println!("{}", s);\n}\n\n\n✅ Solution correcte (via un paramètre) :
\nfn get_reference<'a>(input: &'a str) -> &'a str {\n input // Retourne une référence avec la même durée de vie\n}\n\nfn main() {\n let data = String::from("test");\n let result = get_reference(&data);\n println!("{}", re