Journal
Progression
Section intitulée « Progression »- Leçon 1 — Chaîne d’outils et Cargo
- Leçon 2 — Types, mutabilité et expressions
- Leçon 3 — Possession et déplacements
- Leçon 4 — Emprunts et chaînes
- Leçon 5 — Structs, enums et pattern matching
- Leçon 6 —
Option,Resultet? - Leçon 7 — Traits et génériques
- Leçon 8 — Collections et itérateurs
- Leçon 9 — Durées de vie (lifetimes)
- Leçon 10 — Modules, crates et workspaces
- Leçon 11 —
Box,Rc,Arc,RefCell - Leçon 12 — Threads,
Send/Sync,Mutex, rayon - Leçon 13 —
asyncet tokio - Leçon 14 — Tests, docs, clippy, fmt
- Leçon 15 — Macros,
unsafeet FFI
2026-09-13 — Leçons 1 à 4
Section intitulée « 2026-09-13 — Leçons 1 à 4 »- Chaîne d’outils sur ma machine :
rustc 1.94.0,cargo 1.94.0, édition 2024 par défaut pourcargo new. - Chaque extrait a été compilé avant d’être intégré à une leçon ; les erreurs du compilateur sont copiées depuis la sortie réelle de
rustc(seules les longues notes « other types implement this trait » ont été raccourcies). - Le code du cours se trouve dans
code/rust-for-csharp-java: desexamples/exécutables et des doctestscompile_faildanssrc/lib.rs, vérifiés par le workflow GitHub Rust course examples.
Surprises en venant de C# :
- Le dépassement d’entier panique dans les builds debug mais reboucle dans les builds release — vérifié avec
255u8 + 1compilé des deux façons. C# reboucle dans les deux cas, sauf avecchecked. - Clippy a signalé
let scores = vec![90, 72, 85, 60];commeuseless_vec, car le vecteur n’était jamais lu que comme une slice — un tableau suffirait. - L’erreur du borrow checker pour « push pendant l’itération » est la version à la compilation de
InvalidOperationException: Collection was modified.
Réponse : compile_fail,E0382 vérifie-t-il le code d’erreur ? Pas en stable. Un doctest marqué compile_fail,E0999 autour d’une utilisation après déplacement (en réalité E0382) passe quand même avec cargo test --doc en 1.94.0 — la version stable vérifie seulement que la compilation échoue. Le workflow CI lance désormais aussi cargo +nightly test --doc, qui compare les codes.
2026-09-13 — Leçons 5 à 8
Section intitulée « 2026-09-13 — Leçons 5 à 8 »Chaque solution d’exercice est désormais aussi un doctest : 41 doctests au total (extraits compile-fail et solutions), tous au vert en 1.94.0.
Erreurs attrapées par les tests avant publication :
- J’ai d’abord écrit
prices.sort_by(|a, b| a.total_cmp(b))survec![19.99, 5.0, 12.5]. Cela ne compile pas : les littéraux sont encore un{float}non déterminé au moment où la closure est vérifiée (E0599: no method named total_cmp found for reference &{float}). AnnoterVec<f64>corrige le problème — la leçon 8 l’explique désormais. - Dans la leçon 7, j’affirmais que
cheapestpouvait prendre unVec<Box<dyn Priced>>avec une contrainteT: Priced + ?Sized. Faux :&[T]exigeT: Sized. La version qui fonctionne implémentePricedpourBox<dyn Priced>, et c’est ce que l’exercice montre (et teste) désormais. - Clippy a rejeté
(1..=5).fold(1, |acc, n| acc * n)au profit de.product()(unnecessary_fold) ; l’exemple defoldcalcule donc plutôt une paire min/max — ce qu’aucun adaptateur seul ne fait.
Surprises en venant de C# :
- Quand
mainrenvoieErr, Rust affiche l’erreur avec son formatDebug(Error: Missing("port")), et nonDisplay, puis se termine avec le code 1. Vec<f64>::sort()ne compile pas du tout (f64n’est pasOrd), là où C# et Java trient les doubles en silence.- Le message
E0004pour une nouvelle variante d’enum nomme exactement le motif manquant (&Payment::Crypto { .. } not covered) — mieux que tous les avertissements d’analyseur C# que je connais.
2026-09-13 — Leçons 9 à 12
Section intitulée « 2026-09-13 — Leçons 9 à 12 »76 doctests désormais (stable et nightly), plus un vrai workspace de deux crates pour la leçon 10 (code/rust-for-csharp-java/l10-workspace) que la CI teste, analyse (lint) et exécute. La crate du cours a gagné sa première dépendance : rayon, en dev-dependency.
Ce que j’ai d’abord mal fait :
- Dans l’exemple de la leçon 9, j’utilisais
drop(parser)pour montrer que les tokens survivent au parser. Clippy l’a refusé (drop_non_drop) : appelerdropsur un type sans implémentation deDropne sert à rien. Une fonctiontokenizedont le parser local meurt à la fin fait mieux la démonstration. - Clippy m’a aussi appris
u64::is_multiple_of(manual_is_multiple_of) au lieu den % d != 0. - Je pensais qu’un
maprayon qui modifie un compteur capturé échouerait avec une erreurSend/Sync. Il échoue plus tôt : les closures de rayon sontFn, donc c’estE0594: cannot assign to a captured variable in a Fn closure.
Surprises :
- Le message de panique de
RefCellen 1.94 est simplementRefCell already borrowed; des supports plus anciens citentalready borrowed: BorrowMutError. - Écrire
&strau lieu de&'a strcomme type de retour d’une méthode compile sans problème — l’erreur n’apparaît qu’au site d’appel, quand on essaie de garder deux tokens (E0499). L’élision a choisi la durée de vie de&mut self. - Un enum récursif sans
BoxdonneE0391(un cycle dans la requête « needs drop » du compilateur) en plus deE0072. - rayon sur cette machine (Core Ultra 9 285K, 24 cœurs) : compter les nombres premiers inférieurs à 5 000 000 est passé de ~775 ms à ~41 ms, environ 18×.
2026-09-13 — Leçons 13 à 15, et trois systèmes d’exploitation
Section intitulée « 2026-09-13 — Leçons 13 à 15, et trois systèmes d’exploitation »Le cœur du cours est terminé. Le code a désormais tokio en dev-dependency, deux petites crates de plus (l14-testing, et l15-ffi avec un client .NET 10), et la CI exécute tout sous Windows, Ubuntu et macOS. Le programme C# appelle la bibliothèque Rust avec succès sur les trois.
Ce que j’ai d’abord mal fait :
- Le test FFI de la leçon 15 affirmait
pricing_sum([19.99, 5.0, 12.5]) == 37.49. La vraie somme enf64vaut37.489999999999995; C# n’avait affiché37.49qu’à cause de son formatF2. - Un commentaire XML du
.csprojcontenait--release: MSBuild refuse de charger un projet dont un commentaire contient--. - J’avais écrit que
[LibraryImport]marshale par défaut unboolcomme unBOOLde 4 octets. Il n’a en fait aucun comportement par défaut : le build échoue avecSYSLIB1051tant qu’on n’ajoute pas[MarshalAs]. C’était le comportement de[DllImport]. cargo fmt --check --manifest-path …fonctionnait sur ma machine (Cargo 1.94) mais échouait sur les runners de CI (Cargo 1.98.1) avecFailed to find targets. La CI lance désormaiscargo fmt --checkdepuis le dossier de chaque crate.missing_docs = "warn"dans[lints]s’applique aussi aux tests d’intégration : chaque fichier detests/est sa propre crate et a besoin d’une ligne//!.- Un doctest de la leçon 13 affirmait que trois attentes concurrentes se terminent en moins de 290 ms. C’est vrai sur ma machine, mais une assertion de durée donne un test instable (flaky) sur des runners de CI partagés ; le test ne vérifie donc plus que les résultats.
- Même sans assertion de durée, un délai reste une course : sur un runner macOS chargé, une tentative de 200 ms a « réussi » malgré un
timeoutde 50 ms (quand le runtime se réveille après les deux échéances,timeoutinterroge d’abord le future, déjà prêt). Les tentatives lentes de l’exercice 2 durent maintenant 5 secondes : le test reste rapide, car elles sont abandonnées après 50 ms.
Surprises :
- En Rust asynchrone, un
.awaitoublié signifie que le code ne s’exécute jamais — l’inverse de C#, où la tâche démarre quand même. - L’erreur « future cannot be sent between threads safely » n’a pas de code
E: elle vient de la contrainteSenddetokio::spawn, pas du langage. - L’édition 2024 exige
unsafe extern "C"et#[unsafe(no_mangle)]; une bonne partie des supports FFI plus anciens ne compile plus tels quels. cargo fmtn’avait jamais été lancé sur ce cours : 30 différences de formatage dans les exemples de douze leçons.- Hello world en mode release : environ 130 Ko sous Windows, 430–460 Ko sous Linux et macOS (runners de CI, Cargo 1.98.1).
Questions ouvertes
Section intitulée « Questions ouvertes »- Comment
rust-analyzerdans RustRover se compare-t-il à VS Code pour ces exercices ?