Rust est un langage comme un autre avec ses spécificités. Mais beaucoup s'en font tout un monde (une sorte d'élitisme inutile s'est installé autour de ce langage). J'espère que ce projet vous aidera à franchir le pas, mais n'oubliez pas de lire la documentation officielle (https://doc.rust-lang.org/book/), lire des livres, blog posts et demander aux copains, ...
Vous êtes dans un projet "Gitpodifié", donc vous n'avez rien à installer. Sinon, l'installation de Rust est plutôt triviale, je vous laisse en juger: https://doc.rust-lang.org/book/ch01-01-installation.html
Créez un nouveau projet Rust en utilisant Cargo (le gestionnaire de paquets et de projets de Rust). Dans votre terminal, exécutez :
cargo new 01-hello-world --name hello_world
cd 01-hello-world
Ouvrez le fichier src/main.rs
et remplacez le contenu par :
fn main() {
println!("👋 Hello, World 🌍!");
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Créez un nouveau projet:
cargo new 02-variables --name variables
cd 02-variables
Rust est un langage statiquement typé, donc vous devez déclarer le type de vos variables. Voici un exemple :
fn main() {
let x: i32 = 5;
let y: f64 = 3.14;
let is_rust_cool: bool = true;
println!("x = {}, y = {}, Rust is cool = {}", x, y, is_rust_cool);
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Créez un nouveau projet:
cargo new 03-control-structure --name control_structure
cd 03-control-structure
Utilisez if
, else if
, et else
pour les conditions, et loop
, while
, ou for
pour les boucles :
fn main() {
let number = 7;
if number % 2 == 0 {
println!("Even");
} else {
println!("Odd");
}
for i in 0..5 {
println!("Iteration: {}", i);
}
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Créez un nouveau projet:
cargo new 04-functions --name functions
cd 04-functions
Déclarez des fonctions avec fn
:
fn add(x: i32, y: i32) -> i32 {
x + y
}
fn main() {
let sum = add(3, 4);
println!("Sum: {}", sum);
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Créez un nouveau projet:
cargo new 05-ownership-borrowing --name ownership_borrowing
cd 05-ownership-borrowing
Rust utilise un système de possession unique pour gérer la gestion de la mémoire. Voici un exemple simple :
fn main() {
let s1 = String::from("Hello");
let s2 = s1; // ownership transférée à s2
// println!("{}", s1); // erreur car s1 ne possède plus la chaîne.
println!("{}", s2);
let s3 = String::from("Hello");
let s4 = &s3; // borrowing de l'ownership
println!("{}", s3); // Cela est autorisé grâce au borrowing.
println!("{}", s4);
}
Ensuite, exécutez votre programme avec la commande :
cargo run
et aussi un peu de programmation fonctionnelle
Créez un nouveau projet:
cargo new 06-structs-enums --name structs_enums
cd 06-structs-enums
Définissez des structures de données avec struct
et créez des énumérations avec enum
:
struct Person {
name: String,
age: u32,
}
enum Status {
Success,
Failure(String),
}
fn main() {
let person = Person {
name: String::from("Alice"),
age: 30,
};
match person.age {
0..=17 => println!("Minor"),
18..=64 => println!("Adult"),
_ => println!("Senior"),
}
let result = Status::Success;
match result {
Status::Success => println!("Operation succeeded"),
Status::Failure(msg) => println!("Operation failed with message: {}", msg),
}
}
Ensuite, exécutez votre programme avec la commande :
cargo run
✋ Vous allez avoir quelques warnings, mais pas d'inquétude, ça va quand même s'exécuter:
Celui-ci, c'est parce que vous affectez une valeur à
name
, mais vous ne la lisez pas
warning: field `name` is never read
--> src/main.rs:23:5
|
22 | struct Person {
| ------ field in this struct
23 | name: String,
| ^^^^
|
= note: `#[warn(dead_code)]` on by default
Le compilateur estime que votre
enum
n'est pas "reachable" par le reste du code. Si vous passez votreenum
en publique (pub
), le warning disparaîtra.
warning: variant `Failure` is never constructed
--> src/main.rs:29:5
|
27 | enum Status {
| ------ variant in this enum
28 | Success,
29 | Failure(String),
| ^^^^^^^
Créez un nouveau projet:
cargo new 07-errors --name errors
cd 07-errors
Utilisez Result
pour gérer les erreurs :
fn divide(x: f64, y: f64) -> Result<f64, &'static str> {
if y == 0.0 {
Err("Cannot divide by zero")
} else {
Ok(x / y)
}
}
fn main() {
let result = divide(10.0, 2.0);
match result {
Ok(value) => println!("Result: {}", value),
Err(msg) => println!("Error: {}", msg),
}
}
Ensuite, exécutez votre programme avec la commande :
cargo run
✋ Alors, lorsque l'on vient du JavaScript comme moi, il y a un truc un peu "ésotérique" dans la notation du type de retour de la fonction: Result<f64, &'static str>
(et là tu te dis que les gens qui font du Rust font ça pour pas que l'on fasse du Rust 🤭, je reconnais avoir eu la même impression quand je me suis mis à Scala).
&'static str
est une référence à une chaîne de caractères statique en cas d'erreur 🤔 ... 🤪
Allez, je re-essaie:
La notion de 'static
en Rust se réfère à la durée de vie de la chaîne de caractères et à la manière dont cette chaîne est stockée en mémoire.
Une référence avec une durée de vie 'static
signifie qu'elle pointe vers une région mémoire statique, dont la durée de vie est la totalité de l'exécution du programme. Concrètement, cela signifie que la chaîne de caractères à laquelle elle fait référence est stockée dans une région mémoire qui persiste pendant toute la durée de vie (d'exécution) du programme.
Créez un nouveau projet:
cargo new 08-strings-vectors --name strings_vectors
cd 08-strings-vectors
Rust propose des types de données intégrés tels que String
et Vec
:
fn main() {
// String
let mut greeting = String::from("Hello, ");
greeting.push_str("world!");
println!("{}", greeting);
// Vec
let numbers = vec![1, 2, 3, 4, 5];
for num in &numbers {
println!("{}", num);
}
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Créez un nouveau projet:
cargo new 09-threads --name threads
cd 09-threads
Rust prend en charge le multithreading de manière plutôt simple et intuitive (mais attention, l'exemple est simple):
use std::thread;
use std::time::Duration;
fn main() {
// Créer un vecteur pour stocker les threads
let mut handles = vec![];
for i in 0..5 {
// Créer un nouveau thread pour chaque itération
let handle = thread::spawn(move || {
// Code exécuté dans chaque thread
for j in 0..3 {
println!("Thread {}: Iteration {}", i, j);
thread::sleep(Duration::from_millis(100)); // Simuler une tâche prenant du temps
}
});
// Ajouter le thread au vecteur
handles.push(handle);
}
// Attendre que tous les threads se terminent
for handle in handles {
handle.join().unwrap();
}
}
Ensuite, exécutez votre programme avec la commande :
cargo run
Dans cet exemple, j'ai créé cinq threads, chacun exécutant une boucle. Les threads sont stockés dans un vecteur handles. La fonction thread::sleep
simule une tâche qui prend du temps.
Ensuite, dans la deuxième boucle on attend que tous les threads se terminent à l'aide de la méthode join. Cela permet aux threads de s'exécuter de manière concurrente, affichant leurs sorties (println!("Thread {}: Iteration {}", i, j);
) pendant que le programme principal attend qu'ils se terminent.
✋ vous avez du remarquer le mot clé mut
au moment de la déclaration du vecteur handles
. Le mot-clé mut
est utilisé pour indiquer que la variable est mutable, c'est-à-dire qu'elle peut être modifiée après sa création. Cela s'applique principalement aux variables, mais peut également être utilisé pour rendre des références mutables, des champs de structures mutables, etc ...
Ceci était une introduction (très) rapide à Rust. Il vous reste encore du chemin, mais vous avez de quoi commencer sans stress.
Je vous recommande aussi ces guides d'introduction, complètement complémentaires au mien: