Revue de code Rust : 5 remarques que tout senior fera

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi Rust est-il si strict, et comment la revue de code aide à ne pas perdre la tête

\n

Vous avez écrit du code en Rust. Il s'est compilé — hourra ! Mais voici le problème : le développeur senior, en ouvrant votre Pull Request, soupire et commence à écrire des commentaires. Cela vous dit quelque chose ? Rust est un langage avec une philosophie unique : il vous fait confiance, mais vérifie tout. Cependant, le compilateur ne voit pas ce que voit un œil expérimenté. Il ne dira pas : « Hé, ça peut être fait plus élégamment » ou « Ton code fuit — pas de la mémoire, mais des performances ».

\n

Dans cet article, nous allons effectuer une revue de code Rust et analyser les remarques typiques des seniors. Vous apprendrez à transformer un « code qui fonctionne juste » en un code idiomatique et fiable. C'est parti !

\n\n

1. Ignorer le système de types : « Et si je mettais tout dans un String »

\n

L'erreur la plus fréquente des débutants est d'utiliser String ou des types génériques là où des types spécifiques sont nécessaires. Le senior dira : « Ton type doit refléter la logique métier, pas juste être une chaîne de caractères ».

\n

Problème : perte de sémantique

\n

Imaginez que vous écrivez une fonction pour travailler avec des adresses email :

\n
fn send_email(to: String, subject: String, body: String) {\n    // ...\n}
\n

Qu'est-ce qui ne va pas ici ? Vous pouvez confondre to et subject — le compilateur ne le remarquera pas. Le senior proposera d'utiliser le newtype-pattern :

\n
struct Email(String);\nstruct Subject(String);\nstruct Body(String);\n\nfn send_email(to: Email, subject: Subject, body: Body) {\n    // ...\n}
\n

Cela semble excessif ? Lors d'une code review Rust, cette approche est la référence. Elle rend le code auto-documenté et élimine toute une classe d'erreurs.

\n\n

2. Abus de clone() : copier ne signifie pas posséder

\n

Les développeurs juniors utilisent souvent .clone() partout où le compilateur se plaint des emprunts. Le senior dira : « Tu abandonnes face au borrow checker. Pense différemment ».

\n

Exemple : clone inutile

\n
fn process(data: Vec<i32>) {\n    let first = data[0].clone();\n    let second = data[1].clone();\n    // ...\n}
\n

i32 implémente le trait Copy — clone() est ici totalement superflu. Mais le problème est plus profond : si vous clonez de grandes structures (comme Vec ou String), vous subissez un impact sur les performances.

\n

La bonne approche est de travailler avec des références :

\n
fn process(data: &[i32]) {\n    let first = &data[0];\n    let second = &data[1];\n    // ...\n}
\n

Lors d'une revue de code Rust, vous devez expliquer pourquoi vous clonez. Si la réponse est « pour que le compilateur ne se plaigne pas » — préparez-vous à un commentaire cinglant.

\n\n

3. Mauvaise gestion des erreurs : .unwrap() n'est pas une solution finale

\n

Les seniors détestent unwrap() et expect() dans le code de production. Pourquoi ? Parce qu'ils transforment une erreur potentiellement récupérable en panique. Et une panique en Rust, c'est une terminaison brutale.

\n

Qu'est-ce qui ne va pas avec ce code ?

\n
let file_content = std::fs::read_to_string("config.txt").unwrap();
\n

Si le fichier n'existe pas — le programme plante. Le senior proposera :

\n
let file_content = std::fs::read_to_string("config.txt")\n    .map_err(|e| format!("Failed to read config: {}", e))?;
\n

Utilisez l'opérateur ? et vos propres types d'erreurs. C'est la base du Rust idiomatique. Lors d'une code review Rust, c'est l'une des premières remarques.

\n\n

4. Performance oubliée : allocations et itérateurs

\n

Rust est un langage système. Le senior regardera non seulement la sécurité, mais aussi la vitesse. L'un des problèmes typiques est la création de collections inutiles.

\n

Exemple : collectionnement inutile

\n
let numbers: Vec<i32> = (0..100).collect();\nlet doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();                

Blogs

Book Recommendations