Skip to content
Snippets Groups Projects
Commit 5833c8e5 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

Adding all existing chapters

parent e3fecb83
No related branches found
No related tags found
No related merge requests found
......@@ -6,12 +6,12 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Build the book first, because mdbook will create any empty sections
echo "Building book"
RUST_LOG=info mdbook build ${SCRIPT_DIR}
RUST_LOG=info mdbook build "${SCRIPT_DIR}"
# Then build the slides
echo "Building slides"
RUST_LOG=debug mdslides --template ${SCRIPT_DIR}/template.html --output-dir ${SCRIPT_DIR}/slides --mdbook-path ${SCRIPT_DIR} --index-template ${SCRIPT_DIR}/index-template.html
RUST_LOG=debug mdslides --template "${SCRIPT_DIR}/template.html" --output-dir "${SCRIPT_DIR}/slides" --mdbook-path "${SCRIPT_DIR}" --index-template "${SCRIPT_DIR}/index-template.html"
# TODO: move assets copying to mdslides
cp -r "${SCRIPT_DIR}/book/figs" "${SCRIPT_DIR}/slides"
# Then run the tests (which is slow)
echo "Testing book"
RUST_LOG=info mdbook test ${SCRIPT_DIR}
\ No newline at end of file
RUST_LOG=info mdbook test "${SCRIPT_DIR}"
\ No newline at end of file
......@@ -17,7 +17,9 @@
- [Traits](traits.md).
- [Tests](tests.md).
- [Vecteurs](vec.md).
- [Les Strings](string.md).
<!-- - [Itérateurs](iterators.md).
- [Unsafe Rust](collections.md).
- [Lifetimes](lifetimes.md). -->
- [Unsafe](unsafe.md).
# Les structures de contrôle
## Les branchements conditionnels
```rust [3-5|6-8|9-11|]
fn main() {
let x = 15;
if x < 10 {
println!("{} est plus petit que 10.", x);
}
else if x >= 10 && x < 20 {
println!("{x} est plus grand ou égal à 10 et plus petit que 20.");
}
else {
println!("{x} est plus grand ou égal à 20.");
}
}
```
## C'est des **expressions**
```rust [2|4-10|4,6,9,10|]
fn main() {
let x = -1;
let sign =
if x > 0 {
1 // pas de ;
} else if x < 0 {
-1 // pas de ;
} else {
0 // pas de ;
}; // attention au ;
}
```
## La boucle infinie: `loop`
```rust [] ignore
fn main() {
let mut x = 0;
loop {
println!("En boucle!");
x += 1;
}
}
```
## Sortie avec `break`
```rust [3,10|8|]
fn main() {
let mut i = 0;
let j = loop {
println!("{}, en boucle!", i);
i += 1;
if i == 10 {
println!("Fin de la boucle!");
break i; // i est optionnel
}
}; // attention au ;
}
```
## La boucle `while`
```rust [3,6|]
fn main() {
let mut i = 0;
while i != 10 {
println!("{}-ème boucle!", i);
i += 1;
}
println!("Fin de la boucle!");
}
```
## La boucle `for` et `continue`
```rust [2,7|3-5|]
fn main() {
for i in 0..10 {
if i % 2 == 0 {
continue;
}
println!("{}-ème boucle!", i);
}
println!("Fin de la boucle!");
}
```
## La boucle `for` ++
```rust ignore
for i in collection {
// instructions
}
```
slides/src/figs/ferris.png

46.2 KiB

slides/src/figs/mem_cp.png

62.9 KiB

slides/src/figs/mem_mv.png

50.2 KiB

slides/src/figs/mem_ref_vec.png

6.95 KiB

slides/src/figs/mem_vec.png

9.13 KiB

......@@ -36,7 +36,7 @@
- Une mascotte super mignonne
![Ferris](figs/ferris.svg)
![Ferris](figs/ferris.png)
## Une brève histoire du Rust
......
......@@ -46,20 +46,26 @@ fn main() {
} // x sort de la portée et sa valeur est détruite
```
## Allocation de la mémoire (1/3)
- Façons principales d'allouer/désallouer dynamiquement de la mémoire.
1. Manuellement (C/C++, ...): on ordonne à l'OS d'allouer/désallouer de la mémoire sur le tas.
a. Oublier de désallouer la mémoire allouée (fuite mémoire/memory leak).
b. Désallouer de la mémoire trop tôt (dangling pointer et comportement indéfini).
c. Libérer la mémoire à double.
2. Automatiquement: on a un "garbage collector" (java, scala, ...).
a. Consomme des ressources.
b. Est une "boîte magique": il fait ce qu'il veut.
## Allocation de la mémoire: Manuelle
* Manuellement (C/C++, ...): on ordonne à l'OS d'allouer/désallouer de la mémoire sur le tas.
- Oublier de désallouer la mémoire allouée (fuite mémoire/memory leak).
- Désallouer de la mémoire trop tôt (dangling pointer et comportement indéfini).
- Libérer la mémoire à double.
## Allocation de la mémoire: Garbage collection
* Automatiquement: on a un "garbage collector" (java, scala, ...).
- Consomme des ressources.
- Est une "boîte magique": il fait ce qu'il veut.
## Allocation de la mémoire: Rust
- En Rust on contrôle où et quand on alloue/désalloue à la compilation:
- Difficulté: il faut suivre des règles **très** strictes.
- Garbage collection "à la compilation".
## Allocation de mémoire (2/3)
## Allocation de mémoire (tas)
- Les types vus jusque là sont stockés dans la pile: leur *taille est connue* à la compilation.
- Que se passe-t-il lorsque la taille est *inconnue à la compilation*?
......@@ -76,9 +82,9 @@ fn main() {
} // x/y sortent de la portée, il sont détruits et la mémoire est libérée
```
## Allocation de mémoire (3/3)
## Allocation de mémoire (Vec)
![La représentation en mémoire du vecteur `v = (1,2,3,4)`](figs/mem_vec.svg)
![La représentation en mémoire du vecteur `v = (1,2,3,4)`](figs/mem_vec.png)
- Pile: 1 pointeur vers le tas, et 2 entiers (longueur et capacité).
- Tas: 1, 2, 3, 4.
......@@ -130,7 +136,7 @@ fn main() {
- En ne faisant rien on a **deux** propriétaires des données.
- Illégal: on invalide `y`.
![](figs/mem_mv.svg)
![](figs/mem_mv.png)
## Exception au `move`: `Copy`
......@@ -150,7 +156,7 @@ fn main() {
- *move*: copie uniquement la variable et le propriétaire **change**.
- *copie*: on duplique la variable **et** les données.
![](figs/mem_cp.svg)
![](figs/mem_cp.png)
## Quand interviennent les `move`?
......@@ -216,7 +222,7 @@ fn main() {
## La référence (schéma)
![](figs/mem_ref_vec.svg)
![](figs/mem_ref_vec.png)
## Exemple 1
......
......@@ -5,28 +5,33 @@
- Un **pointeur** est une variable qui contient une adresse mémoire.
- Cette adresse **pointe** vers des données.
![Illustration: tableau.](figs/mem_ref_vec.svg)
![Illustration: tableau.](figs/mem_ref_vec.png)
- Question: Quel type de pointeur avons-nous déjà rencontré?
- Réponse: La référence.
## Smart pointers
- Un **pointeur intelligent** est un type abstrait qui rajoute des fonctionnalités au poiteur standard.
- Type abstrait qui rajoute des fonctionnalités au poiteur standard.
- Management automatique de la mémoire.
- Vérification de limites.
- En particulier, ils permettent la désallocation de la mémoire de manière automatique:
- On peut avoir plusieurs pointeurs sur un espace mémoire.
- Quand le dernier pointeurs est détruit, l'espace mémoire est désalloué.
- Permet d'empêcher les fuites mémoires.
- Il existe différents types:
- Un pointeur unique est le propriétaire de ses données (quand il est détruit les données aussi).
- On compte le nombre de références sur des données, quand ce nombre tombe à zéro on détruit tout.
- Permettent la désallocation de la mémoire de manière automatique:
- Plusieurs pointeurs sur un espace mémoire.
- Dernier pointeurs est détruit => espace mémoire est désalloué.
- Empêche les fuites mémoires.
## Types de pointeurs
- Différents types:
- Pointeur unique, propriétaire de ses données (quand il est détruit les données aussi).
- Comptage de références sur des données, quand ce nombre tombe à zéro on détruit tout.
- Mutabilité intérieure: les règles de Rust sont imposées à l'exécution.
- Accès atomiques: pas de lecture/écriture concurrente possible sur la valeur pointée.
## En Rust
- Exemples:
- `Vec<T>`, `String`: ces types possèdent de la mémoire et la manipule eux-mêmes.
- `Vec<T>`, `String`: ces types possèdent de la mémoire et la manipulent eux-mêmes.
- Les pointeurs intelligent doivent implémenter deux traits:
- `Deref`: comment on déréférence le pointeur.
- `Drop`: comment on détruit le pointeur.
......
# Les chaînes de caractères
## Généralités
- Deux types de chaînes de caractères: `str` et `String`:
- `str`: *string literal* (stocké explicitement dans l'exécutable).
- `String`: liste dynamique de caractères UTF-8.
- `String` est propriétaire de ses données.
- `str` ne peut être "manipulé" que via `&str`
```rust
let literal = "Le type de literal est &str.";
```
## La structure `String`
```console
ptr # pointeur sur le tas de char
len # nombre d'éléments utilisés
capacity # mémoire allouée
```
## Créer des `String`s
```rust [1|2|3|]
let mut empty = String::new();
let hello = String::from("Hello World!"); // converti depuis un &str
let other_hello = "Hello World!".to_string();
```
## Modifier des `String`s
```rust [1-2|]
let mut s = String::from("Hello");
let s1 = " World!";
s.push_str(&s1); // On peut aussi faire push_str(" World!")
println!("{s}");
```
## Concaténer des `String`s
```rust [1-4|]
let s1 = String::from("Hello");
let s2 = String::from(" World!");
let sum1 = s1 + &s2; // s1 moved
let sum2 = "Hello".to_string() + &s2; // s2 borrowed
println!("{sum1} : {sum2}");
```
## Formatter des `String`s
```rust
let s1 = String::from("Hello");
let s2 = String::from("World");
let formatted = format!("{s1} {s2}!");
println!("{formatted}");
```
## Indexer des `String`
```rust compile_fail
let s = String::from("Hello");
let t = s[0]; // fail
```
```rust
let hello = String::from("Καλημέρα!");
println!("{}", hello.len());
```
## Encodage
* UTF-8 `!=` ASCII: encodage à longueur variable (1 à 4 octets).
* Impossible d'indexer en `O(1)`, car on connaît pas la valeur avant d'avoir lu 1 à 4 octets à chaque fois.
## Mais alors comment faire?
```rust [1-5|6|]
let hello = String::from("Καλημέρα!");
for c in hello.chars() {
print!("{c}");
}
println!("");
println!("index 3: {}", hello.chars().nth(3).unwrap());
```
## Le slice de `String`
* Une tranche de `String` est une référence vers un bout de chaîne d'UTF-8.
* On peut facilement créer des tranches de `String`... invalides.
```rust should_panic
let hello = String::from("Καλημέρα!");
let h = &hello[0..3];
```
......@@ -23,12 +23,12 @@ trait Animal { // définition d'un trait
} // le nombre de méthode est arbitraire
```
## Implémentation d'un trait pour un type (1/2)
## Implémentation d'un trait pour un type
- Tout type qui implémentera un trait devra implémenter **toutes** ses méthodes.
- Le compilateur saura que tout type implémentant un trait peut appeler ses méthodes.
- Un type qui implémente un trait doit implémenter **toutes** ses méthodes.
- Le compilateur sait qu'un type implémentant un trait peut appeler ses méthodes.
```rust
```rust [5-7|8-15|]
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn nom(&self) -> &String;
......@@ -50,9 +50,9 @@ fn main() {
}
```
## Implémentation d'un trait pour un type (2/2)
## Implémentation d'un trait pour deux types
```rust
```rust [15-17|18-25|]
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn nom(&self) -> &String;
......@@ -89,9 +89,9 @@ fn main() {
## Implémentations par défaut
- Il est pratique d'avoir des implémentations par défaut (les mêmes pour tous les types implémentant un trait).
- Pratique d'avoir des implémentations par défaut (les mêmes pour tous les types implémentant un trait).
```rust
```rust [1,3-5,6|]
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn cri_puissant(&self) -> String {
......@@ -110,7 +110,6 @@ impl Animal for Cat { // le bloc où les méthodes du trait sont implémentées
String::from("Miaou")
}
}
fn main() {
let chien = Dog{};
println!("Le cri du chien est {} et son cri puissant est {}.",
......@@ -126,13 +125,12 @@ fn main() {
- Lors de la définition d'un générique, on peut dire au compilateur si le type implémente un trait.
```rust
// Cette fonction ne peut pas foncitonner pour tous les types
```rust [1-5|7-9|10-12|]
// T implémente PartialEq (les opérateurs <, >)
fn max<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b } // si on peut pas comparer a et b
} // cela ne peut pas compiler, d'où
// le PartialOrd
// le PartialOrd
fn main() {
let a = 1;
let b = 7;
......
# Unsafe Rust
* Compilateur **très pointilleux**:
* garanties de sécurité mémoire **très fortes**,
* décidées dès **la compilation**.
* Des fois le compilateur prend **trop de précautions**:
* Peut rejeter un code valide lors d'un doute,
* Rust `unsafe` donne des pouvoirs supplémentaires,
* Tant pis si l'utilisateur·trice les utilise mal.
* Les opérations de bas niveau sont `unsafe` par définition (p.ex. interactions avec l'OS).
# Nouveaux pouvoirs
* Déréférencer un pointeur brut,
* Appeler une fonction ou une méthode `unsafe`,
* Accéder à une variable statique mutable ou la modifier,
* Implémenter trait `unsafe`,
* Accéder aux champs des unions.
# Les blocs `unsafe`
```rust [1-3|4-6]
unsafe {
// code unsafe
};
let bla = unsafe {
// le code peut retourner une valeur
};
```
# Mais attention
* Les garanties mémoires sur les références disparaissent en mode `unsafe`
```rust compile_fail
let a = 12;
unsafe {
let b = &a;
let c = &mut a;
};
```
# Le type pointeur brut
```rust [1-2|3-4]
let a = 12;
let ptr_a: * const i32 = &a as * const i32;
let mut b = 24;
let mut_ptr_b: * mut i32 = &mut b as * mut i32;
```
# Propriétés des pointeurs bruts
* `* const T`/`* mut T`: on ne peut/peut pas modifier la valeur pointée,
* Aucune garantie que le mémoire pointée est valide,
* Pas de libération automatique de la mémoire pointée lors de la sortie de la portée,
* Possibilité d'allouer des données sur le tas: `alloc()` `dealloc()`.
# Déréférencement d'un pointeur brut
```rust [1-3|4-6]
let mut a = 12;
let ptr_a = &a as * const i32;
let mut mut_ptr_a = &mut a as * mut i32;
unsafe {
*mut_ptr_a = 20;
println!("{}, {}", *ptr_a, *mut_ptr_a);
}
```
# Fonction `unsafe`
```rust [1|2]
unsafe fn attention_not_safe() {
// everything in here is implicitly annotated unsafe
}
unsafe {
attention_not_safe();
}
```
# Remarques
* Garder le code `unsafe` aussi petit que possible,
* Aide à trouver où peuvent se trouver les erreurs de mémoire,
* Cacher le code `unsafe` dans une API `safe`,
* Permet de communiquer avec du code "externe" (des lib C),
* Annotation `unsafe` d'un bloc: fait tourner ce code c'est promis il marche,
* Annotation `unsafe fn`: attention cette fonction à des contraintes particulières.
......@@ -106,7 +106,7 @@ fn main() {
}
```
## Lecture d'éléments (2/N)
## Lecture d'éléments (1/3)
```rust compile_fail
struct Int(i32);
......@@ -117,7 +117,7 @@ fn main() {
}
```
## Lecture d'éléments (3/N)
## Lecture d'éléments (2/3)
```rust
fn main() {
......@@ -133,7 +133,7 @@ fn main() {
}
```
## Lecture d'éléments (4/N)
## Lecture d'éléments (3/3)
```rust
fn main() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment