Codage Rust
Workflow
-
S’orienter. Lire les sources de vérité du projet avant d’écrire :
rust-toolchain.toml,Cargo.toml(edition,rust-version,[lints],[workspace]),clippy.toml,rustfmt.toml,.cargo/config.toml, et la configuration CI,justfile,Makefile, ouxtaskpour les commandes de vérification canoniques. Lire le module que vous modifiez et ses voisins ; réutiliser leurs helper, types d’erreur et motifs. Terminé lorsque : vous pouvez nommer l’édition, la MSRV, la politique de lint, chaque entréedisallowed-methods/disallowed-types, et les commandes de vérification du projet. -
Modéliser les types. Concevoir les données avant le contrôle de flux, en suivant Types. Changer une API publique de bibliothèque : lire
references/api.md. Terminé lorsque : chaque invariant dont dépend la modification est encodé dans un type, ou maintenu par unexpectdont le message nomme cet invariant. -
Implémenter en boucle serrée. Travailler par petites étapes et lancer
cargo checkaprès chacune. Lire l’intégralité du diagnostic : sa lignehelp:nomme généralement la correction, etrustc --explain E0502développe un code d’erreur. Pour l’API d’une dépendance, lire sa source à la version verrouillée (Cargo.lock) dans$CARGO_HOME/registry/src/. Les renommages massifs passent par le renommage rust-analyzer ouast-grep;cargo clippy --fixapplique les suggestions applicables automatiquement. Correction de bogue : écrire d’abord le test de régression et le voir échouer. Terminé lorsque : la modification compile sans avertissement sur les lignes que vous avez changées, et tout test de régression a échoué avant la correction puis réussi après. -
Vérifier. Exécuter les commandes du projet de l’étape 1 ; sinon :
cargo fmt --all cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test --workspace --all-features- Projet sans politique
[lints]: exécuter aussicargo clippy --all-targets -- -W clippy::pedanticet corriger les hits sur les lignes que vous avez changées. - Fonctionnalités mutuellement exclusives : remplacer
--all-featurespar chaque ensemble de fonctionnalités testé par CI. cargo nextestignore les doctests : ajoutercargo test --doc.- Documentation publique modifiée :
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features. unsafetouché : exécuterreferences/unsafe.md.- Corriger les lints à la cause. Quand la suppression est appropriée, limiter
#[expect(clippy::lint_name, reason = "...")]au plus petit élément. Terminé lorsque : chaque commande se termine avec le code 0, les lignes que vous avez changées ne génèrent aucun avertissement, et chaque nouvelle suppression porte unereason.
- Projet sans politique
-
Auto-relecture du diff. Relire l’intégralité du
git diff, pas de mémoire, en regardant les Règles et les règles de chaque fichier de référence que la branche du diff touche. Terminé lorsque : chaque hunk est nécessaire à la tâche, le code prototype et lesdbg!/todo!ont disparu, les commentaires de doc correspondent au comportement, et chaque règle applicable s’applique à chaque hunk.
Relecture du code d’autrui : exécuter l’étape 1, exécuter les commandes de l’étape 4 quand c’est possible, puis appliquer l’étape 5 à leur diff. Signaler chaque constat sous la forme chemin:ligne, la règle et la correction.
Règles
Possession
- Emprunter dans les paramètres :
&str,&[T],&Path,&T. PrendreString,Vec<T>ouTpar valeur uniquement lorsque la fonction stocke ou consomme la valeur. - Chaque
.clone()justifie sa place : l’appelant a besoin de la possession, ou la valeur est un handle léger (Arc::clone(&handle)). - Lorsque le vérificateur d’emprunt s’y oppose, restructurer d’abord : raccourcir l’emprunt, emprunter des champs disjoints séparément,
std::mem::take/replace, indices dans unVec. La possession mutable partagée (Rc<RefCell<_>>,Arc<Mutex<_>>) est le dernier recours. - Retourner
impl Iterator<Item = T>quand l’appelant ne fait qu’itérer.
Types
- Rendre les états illégaux irr représentables : un
enumportant des données par état, plutôt que des booléens avec des champsOption; des newtypes pour les ID, unités et valeurs validées (struct Port(NonZeroU16)). - Analyser, ne pas valider : convertir une entrée non fiable une fois à la frontière (
TryFrom,FromStr,#[serde(try_from = "Raw")]) et passer le type analysé vers l’intérieur. - Correspondre exhaustivement sur les
enumque vous possédez. Un bras_n’est correct que si une future variante devrait aussi emprunter cette branche. - Convertir les entiers avec
From/TryFrom;astronque et inverse le signe silencieusement.
Erreurs et paniques
- Bibliothèque : un
enumthiserrorpar domaine d’échec. Binaire :anyhow::Resultavec.context(...). - Les paniques signifient des bogues.
unwrap()vit dans les tests ; le code de production utilise?, ouexpect("...")énonçant l’invariant qui rend l’échec impossible.
Idiomes actuels
Les motifs plus anciens dominent les données d’entraînement. Préférer la forme actuelle quand rust-version le permet ; les nouvelles crates utilisent edition = "2024". clippy::incompatible_msrv détecte les nouvelles API std uniquement ; les fonctionnalités de langage et de Cargo nécessitent cargo +<msrv> check.
| Préférer | Plutôt que | Depuis |
|---|---|---|
std::sync::LazyLock, OnceLock | lazy_static!, once_cell | 1.80, 1.70 |
let Some(x) = opt else { return ... }; | match + retour précoce | 1.65 |
if let Some(x) = a && x > 0 | if let imbriqué | 1.88, edition 2024 |
async fn natif dans les traits | #[async_trait], encore nécessaire pour dyn Trait | 1.75 |
| closures `async | {}, bornes AsyncFn` | |
#[expect(lint, reason = "...")] | #[allow(lint)] | 1.81 |
&raw const x, &raw mut x | ptr::addr_of! | 1.82 |
opt.is_some_and(f), opt.is_none_or(f) | map_or(false, f), map_or(true, f) | 1.70, 1.82 |
std::hint::black_box | criterion::black_box | 1.66 |
[lints] dans Cargo.toml pour politique partagée | #![warn(...)] dans chaque racine de crate | 1.74 |
directives cargo:: dans les scripts de build | cargo: | 1.77 |
Documentation et commentaires
- Les éléments publics obtiennent des doc
///:# Errorssur les fonctions faillibles,# Panicssur celles qui paniquent, des exemples sous forme de doctests utilisant?. - Les commentaires expliquent pourquoi ; le code montre quoi.
Dépendances
- Réutiliser ce dont l’espace de travail dépend déjà (
[workspace.dependencies],cargo tree -i <crate>), et préférer std quand cela couvre le besoin. - Ajouter avec
cargo add(conscient de la MSRV), en n’activant que les fonctionnalités que vous utilisez.
Références
Charger celle qui correspond à la branche sur laquelle vous travaillez :
references/api.md: conception ou modification d’une API publique de bibliothèque, nommage, implémentations de trait, semver.references/errors.md: définition des types d’erreur, propagation, panique vsResult.references/async.md: async, tokio, threads, canaux, verrous, atomiques.references/unsafe.md:unsafe, FFI, pointeurs bruts,Send/Syncmanuels.references/cargo.md:Cargo.toml, espaces de travail, fonctionnalités, profils, scripts de build, choix de crate.references/lints.md: configuration des lints pour une crate ou un espace de travail.references/testing.md: écriture de tests, tests de propriété et de snapshot, benchmarks.references/perf.md: optimisation d’un chemin chaud mesuré.