L’organisation du code en Rust suit un système de modules simple mais puissant. Chaque fichier est un module, chaque dossier est un module avec un mod.rs (Rust 2018) ou un fichier du même nom. Cargo gère les dépendances, la compilation, les tests et la documentation.
7.1 Cargo — Le gestionnaire de projet
Créer un nouveau projet
cargo new mon_projet # binaire (src/main.rs)cargo new --lib ma_lib # librairie (src/lib.rs)
Structure standard
mon_projet/
├── Cargo.toml # métadonnées, dépendances
├── Cargo.lock # versions figées (ne pas éditer)
├── src/
│ ├── main.rs # point d'entrée du binaire
│ └── lib.rs # point d'entrée de la librairie
├── tests/ # tests d'intégration
├── examples/ # exemples d'utilisation
├── benches/ # benchmarks
└── target/ # artefacts de compilation (gitignoré)
Cargo.toml
[package]name = "gradient-aggregator"version = "0.1.0"edition = "2024" # Rust edition (2021 = actuelle, 2024 = future)description = "Aggrégation robuste de gradients pour apprentissage distribué"authors = ["Arthur Danjou"]license = "MIT"repository = "https://github.com/arthurdanjou/gradient-aggregator"[dependencies]# Librairiesserde = { version = "1", features = ["derive"] }serde_json = "1"rayon = "1.8"clap = { version = "4", features = ["derive"] }ndarray = "0.16"pyo3 = { version = "0.22", features = ["extension-module"] }[dependencies.cudarc]version = "0.12"optional = true[features]default = []cuda = ["cudarc"] # feature optionnelle pour accélération GPU[profile.release]lto = true # link-time optimizationcodegen-units = 1 # meilleure optimisation
Commandes essentielles
Commande
Effet
cargo build
Compile (debug)
cargo build --release
Compile (release, optimisé)
cargo run
Compile + exécute
cargo test
Lance les tests
cargo doc --open
Génère la documentation et l’ouvre
cargo check
Vérifie la compilation sans produire de binaire (rapide)
cargo clippy
Linter (nombreuses suggestions)
cargo fmt
Formate le code
cargo add serde
Ajoute une dépendance
cargo update
Met à jour Cargo.lock
cargo bench
Lance les benchmarks
cargo publish
Publie sur crates.io
7.2 Modules
Déclaration de modules
// src/lib.rspub mod gar; // charge src/gar.rs ou src/gar/mod.rsmod utils; // module privé (pas accessible depuis l'extérieur)pub use gar::aggregate; // ré-exporter
// src/gar.rs — module "gar"// Les sous-modules vont dans un dossier src/gar/pub mod median;pub mod krum;mod internal; // privé, même à l'intérieur du cratepub trait Gar: Send + Sync { fn aggregate(&self, grads: &[Vec<f64>]) -> Vec<f64>;}
// src/gar/median.rsuse crate::gar::Gar;pub struct Median;impl Gar for Median { fn aggregate(&self, grads: &[Vec<f64>]) -> Vec<f64> { let d = grads[0].len(); let mut result = Vec::with_capacity(d); for j in 0..d { let mut col: Vec<_> = grads.iter().map(|g| g[j]).collect(); col.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); result.push(col[col.len() / 2]); } result }}
Visibilité
Mot-clé
Visible depuis
fn foo() (privé)
Module courant et sous-modules
pub fn foo()
Partout
pub(crate) fn foo()
Dans tout le crate (pas à l’extérieur)
pub(super) fn foo()
Module parent seulement
pub(in path::to::module)
Module spécifique
// Règles de visibilitémod outer { fn private() {} pub fn public() {} pub(crate) fn crate_visible() {} pub(super) fn parent_visible() {} mod inner { // Peut appeler private() (module enfant) // Peut appeler public() (pub) // Peut appeler crate_visible() (même crate) // Peut appeler parent_visible() (super = outer) }}
# gradient-pyo3/Cargo.toml — dépend du core[dependencies]gradient-core = { path = "../gradient-core" }pyo3 = { version = "0.22", features = ["extension-module"] }
7.4 Path et Utilisation
// Chemin absolu depuis la racine du crateuse crate::gar::median::Median;// Chemin relatifuse super::gar::Gar;use self::internal::helper;// Aliasuse crate::gar::krum::Krum as KrumGar;// Ré-exportpub use crate::gar::median::Median;// Import de tout ce qui est pub dans un moduleuse crate::gar::*; // attention : peut importer des choses inattendues// Import imbriqué (Rust 2018+)use crate::gar::{self, median::Median, krum::Krum};