Bienvenue, ami(e) Pascalien(ne) 👋
Ce site est pensé pour les développeurs Object Pascal / Delphi qui veulent apprendre Rust. Chaque concept est illustré par un parallèle de syntaxe Delphi ↔ Rust, et les spécificités de Rust (ownership, borrowing, traits…) sont expliquées en termes Pascalien.
🛡️ Sécurité mémoire
Pas de garbage collector, pas de nil sauvage : le compilateur
garantit l'absence de fuites, de double-free, et de courses à la donnée.
⚡ Performances natives
Binaires natifs (comme Delphi), zero-cost abstractions, performances comparables à C++.
🧰 Outillage moderne
cargo = build + paquet + test + doc. Comparé à
l'écosystème Delphi, l'outillage est unifié et standardisé.
🔀 Concurrence sûre
"Fearless concurrency" : le compilateur empêche les data races à la compilation. Plus de TThread fragile.
Pourquoi un développeur Delphi devrait s'intéresser à Rust ?
- Mêmes valeurs : compilation native, typage fort, structures (
record↔struct),begin/end↔{ }. - Ce que Delphi n'offre pas : un système de propriété qui élimine 70 % des bugs runtime (Access Violation, fuites, race conditions).
- Pas de RTL propriétaire : la bibliothèque standard est open-source, multiplateforme, et l'écosystème (
crates.io) compte plus de 150 000 paquets. - Embarqué & WebAssembly : Rust cible aussi bien le microcontrôleur que le navigateur, là où Delphi est essentiellement Windows/desktop.
Comparatif Rust face aux autres langages
Petit tour d'horizon pour situer Rust dans le paysage que vous connaissez :
| Critère | Rust | Object Pascal (Delphi) | C++ | C# | Java | Python | VBA |
|---|---|---|---|---|---|---|---|
| Compilation | Native | Native | Native | JIT (IL) | JIT (bytecode) | Interprété | Interprété |
| Gestion mémoire | Ownership (compile-time) | Manuelle (Free) + ARC interfaces | Manuelle / RAII | GC | GC | GC | GC |
| Sécurité mémoire | Garantie statique | Faible | Faible | Bonne (GC) | Bonne (GC) | Bonne | Bonne |
| Null / nil | Aucun (Option<T>) | nil | nullptr | null (+ nullable) | null | None | Nothing |
| Exceptions | Non (Result) | Oui | Oui | Oui | Oui | Oui | Oui (On Error) |
| Concurrence sûre | Statique | Manuelle (TThread) | Manuelle | Tasks | Threads | GIL | Non |
| Héritage de classes | Non (traits + composition) | Oui (simple) | Oui (multiple) | Oui (simple) | Oui (simple) | Oui (multiple) | Limité |
| Vitesse exécution | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐ |
| Multiplateforme | Excellent | Bon (FMX) | Excellent | Bon (.NET) | Excellent | Excellent | Office only |
| Outillage standard | cargo ✨ | IDE Delphi | CMake/vcpkg/... | dotnet CLI | Maven/Gradle | pip/poetry | Aucun |
Installation & premier projet
Sous Windows (équivalent Pascalien : l'installeur Delphi) :
- Téléchargez l'installateur officiel sur rustup.rs
- L'outil
rustupinstallerustc(compilateur) etcargo(build/paquet). - Vérifiez :
rustc --version cargo --version - Créez votre premier projet :
cargo new bonjour cd bonjour cargo run
Cargo génère src/main.rs. C'est l'équivalent du fichier .dpr de Delphi
(le point d'entrée), mais ici tout est unifié : le manifest Cargo.toml
joue le rôle du fichier projet (.dproj).
program Bonjour;
{$APPTYPE CONSOLE}
begin
Writeln('Bonjour, monde !');
end.
fn main() {
println!("Bonjour, monde !");
}
println! avec un point d'exclamation est une macro
(résolue à la compilation), pas une fonction : en Rust, c'est une convention
pour repérer immédiatement qu'on appelle du code généré.
Variables & types primitifs
En Delphi, on déclare ses variables dans un bloc var. En Rust, on
utilise let, et — surprise pour un Pascalien — les variables sont
immuables par défaut. Il faut let mut pour pouvoir
modifier une valeur.
var
age: Integer;
nom: string;
pi: Double;
actif: Boolean;
begin
age := 30;
nom := 'Bertrand';
pi := 3.14159;
actif := True;
age := age + 1; // modifiable
end;
fn main() {
let age: i32 = 30; // immuable
let nom: &str = "Bertrand";
let pi: f64 = 3.14159;
let actif: bool = true;
let mut compteur = 0; // mutable
compteur += 1;
// age = age + 1; // ❌ erreur de compilation !
}
Tableau de correspondance des types
| Delphi | Rust | Note |
|---|---|---|
Byte | u8 | 0..255 |
ShortInt | i8 | -128..127 |
Word | u16 | |
SmallInt | i16 | |
Cardinal | u32 | |
Integer | i32 | défaut entier en Rust |
Int64 | i64 | |
NativeInt | isize | taille du pointeur |
NativeUInt | usize | indices de tableau |
Single | f32 | |
Double | f64 | défaut flottant en Rust |
Boolean | bool | true / false |
Char | char | 4 octets en Rust (Unicode complet) |
string | String / &str | deux types, voir Ownership |
array[0..9] of T | [T; 10] | taille fixe |
TArray<T> | Vec<T> | taille dynamique |
Constantes et inférence
const
MAX_AGE = 150;
GREETING: string = 'Salut';
const MAX_AGE: u32 = 150;
const GREETING: &str = "Salut";
let x = 42; // type inféré : i32
let y = 3.14; // f64
let z = "hello"; // &str
let et même changer son type. C'est
sans équivalent direct en Pascal.
let valeur = "42"; // &str
let valeur: i32 = valeur.parse().unwrap(); // i32 maintenant
Contrôle de flux
If / then / else
if age >= 18 then
Writeln('Majeur')
else
Writeln('Mineur');
if age >= 18 {
println!("Majeur");
} else {
println!("Mineur");
}
// if est une EXPRESSION : il retourne une valeur
let statut = if age >= 18 { "Majeur" } else { "Mineur" };
Boucles
// For
for i := 0 to 9 do
Writeln(i);
// While
while x < 100 do
Inc(x);
// Repeat
repeat
x := x - 1;
until x = 0;
// For-in (TArray, TList…)
for item in liste do
Writeln(item);
// For sur une plage (0 inclus, 10 exclu)
for i in 0..10 {
println!("{i}");
}
// While
while x < 100 {
x += 1;
}
// loop = boucle infinie (équivalent du while true)
let resultat = loop {
x -= 1;
if x == 0 { break 42; } // loop peut renvoyer une valeur !
};
// For-in
for item in &liste {
println!("{item}");
}
Case / Match
Le match de Rust est bien plus puissant que le
case Delphi : il fait du pattern matching, vérifie
l'exhaustivité à la compilation, et peut destructurer des types complexes.
case jour of
1: Writeln('Lundi');
2: Writeln('Mardi');
3..5: Writeln('Milieu de semaine');
else
Writeln('Week-end');
end;
match jour {
1 => println!("Lundi"),
2 => println!("Mardi"),
3..=5 => println!("Milieu de semaine"),
_ => println!("Week-end"), // _ = wildcard (obligatoire si non-exhaustif)
}
// match est une EXPRESSION
let nom = match jour {
1 => "Lundi",
2 => "Mardi",
_ => "Autre",
};
Fonctions & procédures
En Pascal, vous distinguez function et procedure.
En Rust, il n'y a que fn : une "procédure" est simplement une
fonction qui retourne le type vide () (appelé "unit").
function Additionner(a, b: Integer): Integer;
begin
Result := a + b;
end;
procedure Saluer(const nom: string);
begin
Writeln('Bonjour ', nom);
end;
fn additionner(a: i32, b: i32) -> i32 {
a + b // pas de ; → c'est l'expression retournée
}
fn saluer(nom: &str) {
println!("Bonjour {nom}");
}
// On peut aussi écrire :
fn additionner_v2(a: i32, b: i32) -> i32 {
return a + b; // explicite, mais moins idiomatique
}
; en fin de
bloc est la valeur de retour. C'est l'inverse de Pascal où le ;
sépare les instructions. Cela rend le code très concis.
Paramètres : valeur, référence, mutabilité
// Passage par valeur
procedure ParValeur(x: Integer);
// const = lecture seule, possible référence
procedure ParConst(const s: string);
// var = par référence (modifiable)
procedure ParVar(var x: Integer);
// out = sortie pure
procedure ParOut(out x: Integer);
// Passage par valeur (déplace ou copie)
fn par_valeur(x: i32) { /* ... */ }
// Référence immuable (≈ const en Delphi)
fn par_ref(s: &String) { /* lecture seule */ }
// Référence mutable (≈ var)
fn par_ref_mut(x: &mut i32) {
*x += 1; // déréférence avec *
}
// Appel :
let mut n = 10;
par_ref_mut(&mut n);
Structures & énumérations
Le record Pascal correspond à la struct Rust.
Mais Rust offre aussi des enums algébriques qui n'ont pas
d'équivalent en Delphi : chaque variant peut porter ses propres données.
Structs
type
TPersonne = record
Nom: string;
Age: Integer;
end;
var
p: TPersonne;
begin
p.Nom := 'Ada';
p.Age := 36;
Writeln(p.Nom);
end;
struct Personne {
nom: String,
age: u32,
}
fn main() {
let p = Personne {
nom: String::from("Ada"),
age: 36,
};
println!("{}", p.nom);
}
Méthodes (impl)
En Pascal, on ajoute des méthodes dans le type. En Rust, on les
regroupe dans un bloc impl séparé : c'est plus net.
type
TRectangle = record
L, H: Double;
function Aire: Double;
end;
function TRectangle.Aire: Double;
begin
Result := L * H;
end;
struct Rectangle {
l: f64,
h: f64,
}
impl Rectangle {
// "Constructeur" associé (sans self)
fn nouveau(l: f64, h: f64) -> Self {
Self { l, h }
}
// Méthode (avec &self)
fn aire(&self) -> f64 {
self.l * self.h
}
}
let r = Rectangle::nouveau(3.0, 4.0);
println!("{}", r.aire());
Énumérations algébriques
L'enum Delphi est juste un ensemble de valeurs nommées. L'enum Rust peut porter des données par variant, ce qui est l'équivalent d'une union discriminée ou d'un sealed class en C#/Java.
type
TForme = (fCercle, fCarre, fTriangle);
// Pour porter des données, on combine
// avec un record variant — assez verbeux :
type
TFormeData = record
case Kind: TForme of
fCercle: (Rayon: Double);
fCarre: (Cote: Double);
fTriangle: (B, H: Double);
end;
enum Forme {
Cercle(f64), // rayon
Carre(f64), // côté
Triangle { base: f64, hauteur: f64 },
}
fn aire(f: &Forme) -> f64 {
match f { // exhaustivité vérifiée !
Forme::Cercle(r) => std::f64::consts::PI * r * r,
Forme::Carre(c) => c * c,
Forme::Triangle { base, hauteur } => base * hauteur / 2.0,
}
}
match, l'enum
Rust rend impossibles les états invalides. Si vous ajoutez un nouveau variant
Forme::Hexagone, le compilateur refuse de compiler tant que vous
n'avez pas géré ce cas partout. Bye-bye les bugs "j'ai oublié un cas du case".
Le type Option<T> — la fin du nil pointer exception
C'est l'une des grandes réussites de Rust : il n'y a tout simplement
pas de nil/null. On utilise l'enum
standard Option<T>.
enum Option<T> {
Some(T),
None,
}
fn chercher(id: u32) -> Option<Personne> {
if id == 1 {
Some(Personne { nom: String::from("Ada"), age: 36 })
} else {
None
}
}
match chercher(1) {
Some(p) => println!("Trouvé : {}", p.nom),
None => println!("Pas trouvé"),
}
En Delphi, il faut systématiquement tester if p <> nil then …
— et on oublie parfois, d'où les fameux Access Violation. En Rust,
impossible d'utiliser le contenu sans avoir explicitement géré le cas None.
Modules & visibilité
L'unit Pascal avec ses sections interface /
implementation correspond au mod Rust avec le mot-clé
pub pour rendre publique une entité.
unit Math;
interface
function Carre(x: Integer): Integer;
function Cube(x: Integer): Integer;
implementation
function Carre(x: Integer): Integer;
begin Result := x * x; end;
function Cube(x: Integer): Integer;
begin Result := x * x * x; end;
end.
// usage :
uses Math;
Writeln(Carre(5));
// Tout ce qui est marqué `pub` est exporté
pub fn carre(x: i32) -> i32 {
x * x
}
pub fn cube(x: i32) -> i32 {
x * x * x
}
fn helper_prive(x: i32) -> i32 {
x + 1
}
// dans src/main.rs :
mod math; // déclare le module
use math::carre; // équivaut au `uses` de Pascal
fn main() {
println!("{}", carre(5));
}
POO en Rust : Traits vs Classes Delphi
Choc culturel pour un Delphiste : Rust n'a pas de classes et pas d'héritage. À la place :
structpour les données (≈record),implpour les méthodes attachées,traitpour les comportements partagés (≈interfaceDelphi),- Composition au lieu d'héritage.
Traits ≈ Interfaces
type
IAnimal = interface
function Crier: string;
end;
TChien = class(TInterfacedObject, IAnimal)
function Crier: string;
end;
TChat = class(TInterfacedObject, IAnimal)
function Crier: string;
end;
function TChien.Crier: string;
begin Result := 'Wouf !'; end;
function TChat.Crier: string;
begin Result := 'Miaou'; end;
trait Animal {
fn crier(&self) -> String;
// méthode par défaut (mixin)
fn presenter(&self) {
println!("Je dis : {}", self.crier());
}
}
struct Chien;
struct Chat;
impl Animal for Chien {
fn crier(&self) -> String {
String::from("Wouf !")
}
}
impl Animal for Chat {
fn crier(&self) -> String {
String::from("Miaou")
}
}
fn main() {
let c = Chien;
c.presenter(); // utilise la méthode par défaut
}
Polymorphisme : dynamique ou statique
En Delphi, le polymorphisme passe par les méthodes virtuelles et les interfaces. En Rust, on a deux options :
- Statique (générique) : résolu à la compilation, zéro coût runtime.
- Dynamique (
dyn Trait) : équivalent vtable Delphi.
// Statique : monomorphisé à la compilation
fn faire_crier<A: Animal>(a: &A) {
println!("{}", a.crier());
}
// Dynamique : vtable, comme une interface Delphi
fn faire_crier_dyn(a: &dyn Animal) {
println!("{}", a.crier());
}
let animaux: Vec<Box<dyn Animal>> = vec![
Box::new(Chien),
Box::new(Chat),
];
for a in &animaux {
a.presenter();
}
trait B: A { … }), ce qui couvre la plupart des cas légitimes
d'héritage.
⭐ Ownership : LA spécificité Rust
Si vous ne deviez retenir qu'un seul concept de Rust, ce serait
celui-ci. L'ownership (propriété) remplace à la fois le garbage
collector des langages managés ET le couple Create/Free
manuel de Delphi.
Les 3 règles d'or
- Chaque valeur a un unique propriétaire (une variable).
- Quand le propriétaire sort du scope, la valeur est libérée automatiquement.
- Affecter une valeur à une autre variable la déplace (move) — l'ancien propriétaire n'y a plus accès.
Le problème en Delphi
var
a, b: TStringList;
begin
a := TStringList.Create;
a.Add('coucou');
b := a; // a et b pointent vers le MÊME objet
b.Free; // OK
a.Add('encore'); // ❌ ACCESS VIOLATION : a est dangling
end;
Pas d'erreur à la compilation. L'erreur n'apparaît qu'à l'exécution, peut-être sur le poste du client.
La solution en Rust
fn main() {
let a = String::from("coucou");
let b = a; // ↘ MOVE : a n'est plus utilisable
// println!("{}", a); // ❌ erreur de COMPILATION
println!("{}", b); // ✅
} // b sort du scope → mémoire libérée automatiquement
L'erreur est attrapée au moment du build. Pas de dangling pointer possible.
Copy vs Move
Les types simples (entiers, flottants, bool, char) implémentent le trait
Copy : l'affectation les duplique, comme en Pascal.
let x = 5;
let y = x; // copie (Copy)
println!("{} {}", x, y); // ✅ les deux marchent
let s = String::from("hello");
let t = s; // move (pas de Copy)
// println!("{}", s); // ❌
println!("{}", t);
Et si je veux vraiment dupliquer ?
let s = String::from("hello");
let t = s.clone(); // copie profonde explicite
println!("{} et {}", s, t); // ✅
En Delphi, b := a sur un objet recopie le pointeur silencieusement.
En Rust, soit c'est Copy (bon marché), soit c'est Move
(transfert), soit on appelle explicitement .clone(). C'est verbeux
mais sans surprise.
⭐ Borrowing & Lifetimes
"Tout déplacer / tout cloner" serait vite pénible. Rust propose un système d'emprunts (références) avec des règles strictes vérifiées par le compilateur.
Les règles d'emprunt
- Vous pouvez avoir plusieurs références immuables (
&T) en même temps, OU - Une seule référence mutable (
&mut T), JAMAIS les deux à la fois. - Une référence ne peut pas survivre à la donnée qu'elle référence (pas de dangling pointer).
fn longueur(s: &String) -> usize { // emprunt immuable
s.len()
} // s sort du scope mais ne libère rien
fn ajouter(s: &mut String) { // emprunt mutable
s.push_str(" !");
}
fn main() {
let mut texte = String::from("Bonjour");
let len = longueur(&texte); // emprunt en lecture
ajouter(&mut texte); // emprunt en écriture
println!("{} ({} caractères)", texte, len);
}
Analogie Delphi
C'est l'équivalent de :
&T↔const T(lecture seule, multiple readers)&mut T↔var T(écriture, unique writer)
… sauf que Delphi vous fait juste confiance, alors que Rust vérifie.
Lifetimes (durées de vie)
Dans 90 % des cas, le compilateur déduit les lifetimes tout seul (élision).
Mais parfois vous devez les annoter avec 'a :
// "La référence retournée vit aussi longtemps que la plus courte des deux entrées"
fn plus_long<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
Cela paraît étrange au début, mais c'est ce qui garantit qu'il n'y a jamais de référence vers une variable détruite.
Gestion d'erreurs : Result au lieu d'exceptions
Delphi utilise les exceptions (try / except / finally). Rust
choisit une approche différente : les erreurs récupérables sont
des valeurs de retour, via l'enum Result<T, E>. Les vraies
situations exceptionnelles (bug logiciel) utilisent panic!, qui
termine le programme.
function Diviser(a, b: Double): Double;
begin
if b = 0 then
raise EDivByZero.Create('Division par zéro');
Result := a / b;
end;
try
x := Diviser(10, 0);
except
on E: EDivByZero do
Writeln('Erreur : ', E.Message);
end;
fn diviser(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Division par zéro"))
} else {
Ok(a / b)
}
}
fn main() {
match diviser(10.0, 0.0) {
Ok(v) => println!("Résultat : {v}"),
Err(e) => println!("Erreur : {e}"),
}
}
L'opérateur ? — propager les erreurs
Pour ne pas écrire un match à chaque appel, Rust propose l'opérateur
? qui retourne automatiquement l'erreur au caller. C'est l'équivalent
d'un except "remonter telle quelle".
fn lire_fichier_puis_parser(chemin: &str) -> Result<i32, std::io::Error> {
let contenu = std::fs::read_to_string(chemin)?; // si erreur → return Err
let n: i32 = contenu.trim().parse().unwrap();
Ok(n)
}
Result) ou pas. En
Delphi/Java/C#, n'importe quel appel peut lever n'importe quelle exception ; on
ne sait jamais quoi attraper.
Génériques & traits avancés
Les génériques Rust sont proches de ceux de Delphi (TList<T>),
mais avec un système de contraintes par trait très expressif.
type
TPaire<T> = record
A, B: T;
end;
function Max<T>(x, y: T): T;
begin
// contrainte difficile : pas de comparaison
// générique standard en Pascal
end;
struct Paire<T> {
a: T,
b: T,
}
// Contrainte : T doit implémenter PartialOrd (comparable)
fn maximum<T: PartialOrd>(x: T, y: T) -> T {
if x > y { x } else { y }
}
// Syntaxe `where` (équivalente, plus lisible avec plusieurs bornes)
fn afficher<T>(v: T) where T: std::fmt::Display + Clone {
let v2 = v.clone();
println!("{v} et {v2}");
}
Le compilateur génère du code spécialisé pour chaque type utilisé (monomorphisation) — comme les génériques C++, donc zéro coût runtime.
Closures & Itérateurs
Rust offre une approche fonctionnelle très riche pour manipuler les collections, équivalente aux LINQ de C# ou aux comprehensions Python — en plus performant car compilé.
var
nombres: TArray<Integer>;
somme: Integer;
i: Integer;
begin
nombres := [1, 2, 3, 4, 5];
somme := 0;
for i in nombres do
if i mod 2 = 0 then
somme := somme + i * i;
// somme = 2² + 4² = 20
end;
fn main() {
let nombres = vec![1, 2, 3, 4, 5];
let somme: i32 = nombres.iter()
.filter(|&&n| n % 2 == 0) // pairs
.map(|&n| n * n) // au carré
.sum(); // somme
println!("{somme}"); // 20
}
Closures (lambdas)
var
carre: TFunc<Integer, Integer>;
begin
carre := function(x: Integer): Integer
begin Result := x * x; end;
Writeln(carre(5));
end;
let carre = |x: i32| x * x;
println!("{}", carre(5));
// closure qui capture une variable de l'environnement
let facteur = 3;
let multiplier = |x| x * facteur;
println!("{}", multiplier(10)); // 30
Concurrence "sans peur"
Le slogan officiel est "fearless concurrency". Le système d'ownership s'étend aux threads : il devient impossible à la compilation d'introduire un data race.
var
t: TThread;
begin
t := TThread.CreateAnonymousThread(
procedure
begin
Writeln('Dans le thread !');
end);
t.Start;
end;
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("Dans le thread !");
});
handle.join().unwrap();
}
Canaux (channels)
Plutôt que de partager de la mémoire avec des verrous, Rust encourage le "share memory by communicating" (à la Go).
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
for i in 1..=3 {
tx.send(i).unwrap();
}
});
for valeur in rx {
println!("Reçu : {valeur}");
}
}
Asynchrone : async / await
async fn telecharger(url: &str) -> String {
// ... requête HTTP non bloquante
format!("contenu de {url}")
}
#[tokio::main]
async fn main() {
let page = telecharger("https://example.com").await;
println!("{page}");
}
Cargo & écosystème
Cargo est le bonheur d'un Delphiste qui découvre l'outillage moderne : une commande, tout marche.
| Action | Delphi | Rust |
|---|---|---|
| Nouveau projet | IDE → File → New → Console | cargo new monapp |
| Compiler (debug) | F9 | cargo build |
| Compiler (release) | changer le mode dans l'IDE | cargo build --release |
| Exécuter | F9 | cargo run |
| Tests | DUnit / DUnitX (à installer) | cargo test (intégré) |
| Ajouter une dépendance | GetIt / manuel | cargo add serde |
| Mettre à jour | manuel | cargo update |
| Documentation | — | cargo doc --open |
| Format du code | — | cargo fmt |
| Linter | — | cargo clippy |
Cargo.toml — le manifest du projet
[package]
name = "monapp"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = "0.12"
L'équivalent du fichier .dproj + GetIt, mais en texte versionnable.
Le site crates.io
recense plus de 150 000 paquets.
Tests intégrés
Pas besoin d'installer DUnitX : les tests sont dans le langage.
fn double(x: i32) -> i32 {
x * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn double_de_zero() {
assert_eq!(double(0), 0);
}
#[test]
fn double_de_cinq() {
assert_eq!(double(5), 10);
}
}
Puis : cargo test. Rust compile et exécute uniquement les
tests, en parallèle.
Récapitulatif : 10 idées clés à emporter
- Immuable par défaut — utilisez
let mutpour la mutation. - Pas de null — utilisez
Option<T>. - Pas d'exceptions — utilisez
Result<T, E>et l'opérateur?. - Ownership remplace GC et
Freemanuel. - Borrowing : références multiples en lecture XOR une seule en écriture.
- Pas de classes ni d'héritage —
struct+trait+ composition. - match est exhaustif : les bugs "oubli d'un cas" disparaissent.
- Enums algébriques = des données par variant + match = états invalides impossibles.
- cargo unifie build, test, doc, dépendances, formatage.
- Concurrence sûre à la compilation — fini les data races sournoises.
Pour aller plus loin
- The Rust Book — le livre officiel (gratuit, en anglais)
- Rust Book interactif (Brown University)
- Rust by Example
- Rustlings — petits exercices interactifs
- Exercism : Rust track
Bonne route dans le monde de Rust 🦀 ! N'hésitez pas à revenir sur cette page comme aide-mémoire : les sections sont indépendantes et conçues pour servir de référence rapide.