Skip to content
Snippets Groups Projects
Commit 8a39dc03 authored by orestis.malaspin's avatar orestis.malaspin Committed by Michaël El Kharroubi
Browse files

Adds summary for part01 and array is copy

parent 1079c46b
No related branches found
No related tags found
No related merge requests found
......@@ -19,4 +19,5 @@ run_test_doc:
- cd codes
- ./run_tests.sh
- cd ../book
- mdbook test
- mdbook build
# Summary
- [Part 00](./part00.md)
- [Part 01](./part01.md)
# Discussion du code `part01`
## Concepts
Les concepts abordés dans cet exemple sont:
1. [Les fonctions.](#les-fonctions)
2. [Les `if ... else` sont des **expressions**.](#en-rust-le-if-est-une-expression)
3. [Itérer sur les éléments d'un tableaux directement avec la boucle for.](#la-boucle-for-revisitée)
## Discussion
### Les fonctions
Dans cette seconde itération de notre programme calculant le minimum d'une liste de nombres,
nous introduisons les **fonctions** en Rust.
La syntaxe d'une fonction est la suivante:
```rust,ignore
fn function_name(arg1: type, arg2: type, ...) -> ReturnType
```
Une fonction est annotée avec le mot-clé `fn` suivi de son identifiant.
Son type de retour se trouve à droite après la *flèche* (en ASCII-art) `->`.
Si une fonction n'a pas de type de retour explicite (il n'y a pas de flèche) le type de retour est `()` qui
rappelle le type `void` de C (aka sans type, mais oui c'est un type en Rust). Entre parenthèses se trouvent les arguments de la fonction suivi de leur type. Le nombre d'arguments est supérieur ou égal à zéro.
Une fonction est ensuite appelée par son identifiant et ses éventuels arguments.
```rust,no_run
const SIZE: usize = 9;
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
// équivalent à return [10, 32, 12, 43, 52, 53, 83, 2, 9];
}
fn main() {
read_command_line();
}
```
La fonction `read_command_line()` ne prend ainsi aucun argument et retourne un tableau statique d'entier 32 bits et de taille `SIZE`.
Pour qu'une fonction retourne une valeur, on a deux solutions:
1. Si la valeur est la dernière expression de la fonction, on peut juste mettre la valeur (ou la variable) sans point virgule à la fin de la ligne.
2. On peut, de façon similaire au C, utiliser le mot clé `return val;`
On constate ici que les tableaux statiques (contrairement à ce qui se passe dans le langage C) peuvent être retournés
par une fonction (le tableau n'est pas désalloué au moment du retour).
La vérification de la taille du tableau se fait dans la fonction `check_size(size: usize)` qui prend donc un argument de
type `usize` et ne retourne rien.
```rust,should_panic
fn check_size(size: usize) {
# if size == 0 {
# panic!("Size is of tab = 0.");
# }
}
# fn main() {
check_size(10); // runs alright
check_size(0); // panics
# }
```
À l'inverse la fonction `print_tab(tab)` prend en argument un tableau statique et ne retourne rien.
```rust
# const SIZE: usize = 9;
# fn read_command_line() -> [i32; SIZE] {
# [10, 32, 12, 43, 52, 53, 83, 2, 9]
# }
fn print_tab(tab: [i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
# fn main() {
let tab = read_command_line();
print_tab(tab);
# }
```
Les fonctions `min_i32(lhs, rhs)` retourne la plus petite valeur de deux entiers signés de 32 bits.
```rust
fn min_i32(lhs: i32, rhs: i32) -> i32 {
if lhs < rhs {
lhs
} else {
rhs
}
}
# fn main() {
let min = min_i32(2, 10);
println!("{min}");
# }
```
### En Rust le `if` est une expression
Mais si vous étudiez attentivement ce code, on constate que le corps de la fonction est étrange.
On voit qu'aucune ligne ne possède de point terminal. Cela voudrait dire que `lhs` ou `rhs` sont la dernière expression
de la fonction. En fait ce qui se passe c'est que le `if ... else` est une **expression**. De façon similaire au
`if` ternaire en `C`, le `if ... else` en Rust retourne une valeur. On peut écrire de façon équivalente au code ci-dessus
```rust
fn min_i32(lhs: i32, rhs: i32) -> i32 {
let min = if lhs < rhs {
lhs
} else {
rhs
};
min
}
# fn main() {
let min = min_i32(2, 10);
println!("{min}");
# }
```
On voit qu'ici à la fin du bloc du `else` nous avons un point virgule qui indique la fin de la ligne.
Ainsi `lhs` ou `rhs` sont liés à la variable immutable `min`.
Cette notion d'expression est très importante. Comme nous l'avons expliqué précédemment la dernière expression d'une fonction est évaluée puis retournée par cette dernière.
Un bloc de code qui produit un résultat est une expression.
En Rust, plusieurs structures de contrôle tel que le `If` sont des expression. Il n'est pas nécessaire de connaître la valeur de l'expression pour la retourner.
Nous pourrions considérer par exemple les fonctions suivante :
```rust,no_run
fn add(lhs: i32, rhs: i32) -> i32 {
lhs + rhs
}
fn add_one(val: i32) -> i32 {
add(1, val)
}
```
### La boucle `for` revisitée
La dernière fonction à discuter est `find_min(tab)` qui retourne la valeur minimale se trouvant dans `tab`.
```rust
# const SIZE: usize = 9;
# fn read_command_line() -> [i32; SIZE] {
# [10, 32, 12, 43, 52, 53, 83, 2, 9]
# }
# fn check_size(size: usize) {
# if size == 0 {
# panic!("Size is of tab = 0.");
# }
# }
# fn min_i32(lhs: i32, rhs: i32) -> i32 {
# if lhs < rhs {
# lhs
# } else {
# rhs
# }
# }
fn find_min(tab: [i32; SIZE]) -> i32 {
check_size(SIZE);
let mut min = i32::MAX;
for t in tab {
min = min_i32(min, t);
}
min
}
# fn main() {
let min = find_min(read_command_line());
println!("The minimal value is: {min}");
# }
```
Cette version du calcul du minimum contient une différence importante dans la syntaxe de la boucle `for`.
En effet, ici on itère pas sur un indice et on accède ensuite aux éléments du tableau.
La syntaxe
```rust,ignore
for val in tab
```
permet d'itérer directement sur les valeurs contenues dans `tab`. Au début de chaque tour de la boucle `for`,
val prend la valeur "courante" du tableau. A la fin du bloc du `for`, la valeur courante prend la valeur "suivante"
dans le tableau si elle existe. En fait le tableau est implicitement converti en *itérateur* (plus de détails plus tard sur le sujet).
Dans d'autres langages on appelle ça une boucle "for each" qui traduit en français signifie *pour chaque*.
Le code ci-dessus est strictement équivalent à
```rust
# const SIZE: usize = 9;
# fn read_command_line() -> [i32; SIZE] {
# [10, 32, 12, 43, 52, 53, 83, 2, 9]
# }
# fn check_size(size: usize) {
# if size == 0 {
# panic!("Size is of tab = 0.");
# }
# }
# fn min_i32(lhs: i32, rhs: i32) -> i32 {
# if lhs < rhs {
# lhs
# } else {
# rhs
# }
# }
fn find_min(tab: [i32; SIZE]) -> i32 {
check_size(SIZE);
let mut min = i32::MAX;
for i in 0..SIZE {
min = min_i32(min, tab[i]);
}
min
}
# fn main() {
let min = find_min(read_command_line());
println!("The minimal value is: {min}");
# }
```
## Le code
```rust
# const SIZE: usize = 9;
# fn read_command_line() -> [i32; SIZE] {
# [10, 32, 12, 43, 52, 53, 83, 2, 9]
# }
# fn check_size(size: usize) {
# if size == 0 {
# panic!("Size is of tab = 0.");
# }
# }
# fn print_tab(tab: [i32; SIZE]) {
# for t in tab {
# print!("{} ", t);
# }
# println!();
# }
# fn min_i32(lhs: i32, rhs: i32) -> i32 {
# if lhs < rhs {
# lhs
# } else {
# rhs
# }
# }
# fn find_min(tab: [i32; SIZE]) -> i32 {
# check_size(SIZE);
# let mut min = i32::MAX;
# for t in tab {
# min = min_i32(min, t);
# }
# min
# }
fn main() {
let tab = read_command_line();
println!("Among the numbers in the list:");
print_tab(tab);
let min = find_min(tab);
println!("The minimal value is: {min}");
}
```
......@@ -3,8 +3,6 @@
/// - Arguments are "moved"
/// - if is an expression
/// - for loops revisited
/// - Tuples
/// - Destructuring
const SIZE: usize = 9;
......@@ -21,12 +19,11 @@ fn check_size(size: usize) {
// Prints tab and returns tab.
// Tab would be destructed at the end of the function otherwise.
fn print_tab(tab: [i32; SIZE]) -> [i32; SIZE] {
fn print_tab(tab: [i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
tab
}
fn min_i32(lhs: i32, rhs: i32) -> i32 {
......@@ -37,23 +34,19 @@ fn min_i32(lhs: i32, rhs: i32) -> i32 {
}
}
fn find_min(tab: [i32; SIZE], size: usize) -> ([i32; SIZE], i32) {
check_size(size);
fn find_min(tab: [i32; SIZE]) -> i32 {
check_size(SIZE);
let mut min = i32::MAX;
for t in tab {
min = min_i32(min, t);
}
(tab, min)
min
}
fn main() {
let tab = read_command_line();
println!("Among the numbers in the list:");
let tab = print_tab(tab);
// There are alternatives to access fields of tuples
let (_, min) = find_min(tab, SIZE);
// The first field is not used therefore we can replace it with "_"
print_tab(tab);
let min = find_min(tab);
println!("The minimal value is: {}", min);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment