Differences

This shows you the differences between two versions of the page.

Link to this comparison view

sde2:laboratoare:01_rust [2023/03/04 20:01]
cristiana.andrei created
sde2:laboratoare:01_rust [2023/03/07 07:57] (current)
cristiana.andrei [Exercises]
Line 1: Line 1:
 ====== TP 01 - Ownership et Arguments du programme ====== ====== TP 01 - Ownership et Arguments du programme ======
 +===== Assignment ===== 
 +<note warning>​ 
 +Vous devez **accepter** le assignment d'ici et travailler avec ce repository: [[https://​classroom.github.com/​a/​8UskEmTM|Lab1]] 
 +</​note>​
 ===== Objectifs ===== ===== Objectifs =====
 Le but de ce TP est d'​apprendre à utiliser ​ Le but de ce TP est d'​apprendre à utiliser ​
Line 9: Line 12:
  
 ===== Resources ===== ===== Resources =====
 +  * Ownership: [[https://​doc.rust-lang.org/​book/​ch04-00-understanding-ownership.html|Documentation]]
 +  * Vectors: [[https://​doc.rust-lang.org/​book/​ch08-01-vectors.html|Documentation]]
 +  * Strings: [[https://​doc.rust-lang.org/​book/​ch08-02-strings.html|Documentation]]
   * Enums [[https://​doc.rust-lang.org/​book/​ch06-00-enums.html|en]],​ [[https://​jimskapt.github.io/​rust-book-fr/​ch06-00-enums.html|fr]]   * Enums [[https://​doc.rust-lang.org/​book/​ch06-00-enums.html|en]],​ [[https://​jimskapt.github.io/​rust-book-fr/​ch06-00-enums.html|fr]]
   * An I/O Project: Building a Command Line Program [[https://​doc.rust-lang.org/​book/​ch12-00-an-io-project.html#​an-io-project-building-a-command-line-program|en]],​ [[https://​jimskapt.github.io/​rust-book-fr/​ch12-00-an-io-project.html|fr]]   * An I/O Project: Building a Command Line Program [[https://​doc.rust-lang.org/​book/​ch12-00-an-io-project.html#​an-io-project-building-a-command-line-program|en]],​ [[https://​jimskapt.github.io/​rust-book-fr/​ch12-00-an-io-project.html|fr]]
Line 209: Line 215:
  
 <​note>​ <​note>​
-Pour comprendre mieux comment definir un enum, lisez [[https://​doc.rust-lang.org/​book/​ch06-01-defining-an-enum.html|cette]] section du chapitre ​5!+Pour comprendre mieux comment definir un enum, lisez [[https://​doc.rust-lang.org/​book/​ch06-01-defining-an-enum.html|cette]] section du chapitre ​6!
 </​note>​ </​note>​
  
Line 263: Line 269:
 } }
 </​code>​ </​code>​
 +Lorsque l'​expression de //match// s'​exécute,​ elle compare la valeur résultante au modèle de chaque bras, dans l'​ordre. Si un modèle correspond à la valeur, le code associé à ce modèle est exécuté. Si ce modèle ne correspond pas à la valeur, l'​exécution continue jusqu'​au bras suivant.
  
 +Le code associé à chaque bras est une **expression**,​ et la valeur résultante de l'​expression dans le bras correspondant est **la valeur renvoyée** pour l'​ensemble de l'​expression de correspondance.
 +
 +Une autre caractéristique utile des bras de match est qu'ils peuvent se **lier** aux parties des valeurs qui correspondent au modèle. C'est ainsi que nous pouvons **extraire** les valeurs des variantes enum.
 +
 +Dans la section précédente,​ nous voulions extraire la valeur T interne du cas Some lors de l'​utilisation de Option<​T>​ ;​ nous pouvons également gérer **Option<​T>​ en utilisant match**, comme nous l'​avons fait avec l'​énumération Coin ! Au lieu de comparer des pièces, nous comparerons les variantes de Option<​T>,​ mais le fonctionnement de l'​expression de correspondance reste le même.
 +
 +<code c>
 +    fn get_option(x:​ Option<​i32>​) -> Option<​i32>​ {
 +        match x {
 +            None => None,
 +            Some(i) => Some(i),
 +        }
 +    }
 +
 +    let five = Some(5);
 +    let six = get_option(five);​
 +    let none = get_option(None);​
 +</​code>​
 +
 +<​note>​
 +Pour comprendre mieux comment match //​fonctionne//,​ lisez [[https://​doc.rust-lang.org/​book/​ch06-02-match.html|cette]] section du chapitre 6!
 +</​note>​
 +
 +===== Vecteurs =====
 +Les **vecteurs** vous permettent de stocker plusieurs valeurs dans une seule structure de données qui place toutes les valeurs les unes à côté des autres en mémoire. Les vecteurs ne peuvent stocker que des valeurs du **même type**.
 +
 +Pour créer un nouveau vecteur vide, nous appelons la fonction **Vec::​new**.
 +<code c>
 +let v: Vec<​i32>​ = Vec::new();
 +</​code>​
 +
 +Lorsque nous créons un vecteur pour contenir un type spécifique,​ nous pouvons spécifier le type entre **crochets**.
 +
 +== Push ==
 +Pour créer un vecteur puis y ajouter des éléments, nous pouvons utiliser la méthode **push**.
 +<code c>
 +    let mut v = Vec::new();
 +
 +    v.push(5);
 +    v.push(6);
 +    v.push(7);
 +    v.push(8);
 +</​code>​
 +Comme pour toute variable, si nous voulons pouvoir changer sa valeur, nous devons la rendre modifiable en utilisant le mot-clé **mut**.
 +
 +== Lire les elements ==
 +Il existe deux façons de référencer une valeur stockée dans un vecteur : via //​l'​indexation//​ ou en utilisant la méthode **get**.
 +<code c>
 +    let v = vec![1, 2, 3, 4, 5];
 +
 +    let third: &i32 = &v[2];
 +    println!("​The third element is {third}"​);​
 +
 +    let third: Option<&​i32>​ = v.get(2);
 +    match third {
 +        Some(third) => println!("​The third element is {third}"​),​
 +        None => println!("​There is no third element."​),​
 +    }
 +</​code>​
 +Rust fournit commodément le **vec!** macro, qui créera un nouveau vecteur contenant les valeurs que vous lui donnez.
 +
 +== Itérer un vecteur ==
 +Pour accéder à tour de rôle à chaque élément d'un vecteur, nous parcourrions tous les éléments plutôt que d'​utiliser des indices pour accéder à un à la fois. L'​example montre comment utiliser une boucle for pour obtenir des références immuables à chaque élément dans un vecteur de valeurs i32 et les imprimer.
 +<code c>
 + let v = vec![100, 32, 57];
 +    for i in &v {
 +        println!("​{i}"​);​
 +    }
 +</​code>​
 +
 +Nous pouvons également itérer sur des **références mutables** à chaque élément dans un vecteur mutable afin d'​apporter des modifications à tous les éléments.
 +<code c>
 +    let mut v = vec![100, 32, 57];
 +    for i in &mut v {
 +        *i += 50;
 +    }
 +</​code>​
 +
 +===== Strings =====
 +Rust n'a qu'un seul type de chaîne dans le langage de base, qui est la tranche de chaîne str qui est généralement vue sous sa forme //​empruntée(borrowed)//​ **&​str**.
 +
 +Le type **String**, qui est fourni par la bibliothèque standard de Rust plutôt que codé dans le langage principal, est un type de chaîne encodé UTF-8 //​évolutif,​ mutable et propriétaire(owned)//​.
 +
 +== Création d'une nouvelle String ==
 +<code c>
 +    let mut s = String::​new();​
 +</​code>​
 +
 +Cette ligne crée une nouvelle chaîne vide appelée s, dans laquelle nous pouvons ensuite charger des données.
 +
 +Nous pouvons utiliser la fonction **String :: from** ou la fonction **to_string()** pour créer une chaîne à partir d'un littéral de chaîne:
 +<code c>
 +    let s = String::​from("​initial contents"​);​
 +</​code>​
 +
 +<code c>
 +let data = "​initial contents";​
 +
 +    let s = data.to_string();​
 +
 +    // the method also works on a literal directly:
 +    let s = "​initial contents"​.to_string();​
 +</​code>​
 +
 +== Ajout à une chaîne ==
 +Nous pouvons développer une chaîne en utilisant la méthode **push_str** pour ajouter une tranche de chaîne.
 +<code c>
 +    let mut s = String::​from("​foo"​);​
 +    s.push_str("​bar"​);​
 +</​code>​
 +
 +La méthode **push** prend **un seul caractère** comme paramètre et l'​ajoute à la chaîne.
 +
 +<code c>
 +    let mut s = String::​from("​lo"​);​
 +    s.push('​l'​);​
 +</​code>​
 +
 +== Méthodes d'​itération sur les chaînes ==
 +La meilleure façon d'​opérer sur des morceaux de chaînes est d'​être explicite quant à savoir si vous voulez des caractères ou des octets. Pour les valeurs scalaires Unicode individuelles,​ utilisez la méthode **chars**.
 +<code c>
 +for c in "​Зд"​.chars() {
 +    println!("​{c}"​);​
 +}
 +</​code>​
 +
 +===== Accepter les arguments de la ligne de commande =====
 +Pour permettre à notre programme de lire les valeurs des arguments de ligne de commande que nous lui transmettons,​ nous aurons besoin de la fonction **std::​env::​args** fournie dans la bibliothèque standard de Rust. Cette fonction renvoie un **itérateur** des arguments de ligne de commande transmis à notre programme.
 +
 +Pour l'​instant,​ vous n'avez besoin de connaître que deux détails sur les itérateurs :​ les itérateurs produisent **une série de valeurs**, et nous pouvons appeler la méthode **collect** sur un itérateur pour le transformer en une collection, telle qu'un vecteur, qui contient tous les éléments produits par l'​itérateur.
 +
 +<code c>
 +use std::env;
 +
 +fn main() {
 +    let args: Vec<​String>​ = env::​args().collect();​
 +    println!(args);​
 +}
 +</​code>​
 +
 +Sur la première ligne de main, nous appelons **env::​args**,​ et nous utilisons immédiatement **collect** pour transformer l'​itérateur en un vecteur contenant toutes les valeurs produites par l'​itérateur.
 +
 +<​note>​
 +La première valeur retournée par env::args est le **nom de notre exécutable**!
 +</​note>​
 +
 +== Enregistrement des valeurs d'​argument dans les variables ==
 +Le programme est actuellement en mesure d'​accéder aux valeurs spécifiées en tant qu'​arguments de ligne de commande. Nous devons maintenant **enregistrer** les valeurs des deux arguments dans des variables afin de pouvoir utiliser les valeurs dans le reste du programme.
 +<code c>
 +use std::env;
 +
 +fn main() {
 +    let args: Vec<​String>​ = env::​args().collect();​
 +
 +    let query = &​args[1];​
 +    let file_path = &​args[2];​
 +
 +    println!("​Searching for {}", query);
 +    println!("​In file {}", file_path);
 +}
 +</​code>​
 ===== Exercises ===== ===== Exercises =====
   - Écrivez une fonction qui reçoit deux nombres comme arguments et les divise. Gérez le cas de la division par zéro à l'aide du type //​Option//​. ​   - Écrivez une fonction qui reçoit deux nombres comme arguments et les divise. Gérez le cas de la division par zéro à l'aide du type //​Option//​. ​
-  - Écrivez un programme qui reçoit deux nombres de la ligne de commande et les divise. Écrivez le résultat à l'​écran. S'il y a une erreur, retournez -1 depuis main. +  - Écrivez un programme qui reçoit deux nombres de la ligne de commande et les divise. Écrivez le résultat à l'​écran. S'il y a une erreur, retournez -1 depuis main. //Hint: [[https://​doc.rust-lang.org/​book/​ch09-02-recoverable-errors-with-result.html|Result]] et [[https://​doc.rust-lang.org/​std/​process/​fn.exit.html#:​~:​text=Function%20std%3A%3Aprocess%3A%3Aexit&​text=Terminates%20the%20current%20process%20with,​for%20consumption%20by%20another%20process.|std::​process::​exit]] //
   - Écrivez un programme qui reçoit en paramètres une commande et deux nombres. La commande est l'une des suivantes : add, sub, mul, div, rem. Écrivez le résultat à l'​écran ou renvoyez une erreur. ​   - Écrivez un programme qui reçoit en paramètres une commande et deux nombres. La commande est l'une des suivantes : add, sub, mul, div, rem. Écrivez le résultat à l'​écran ou renvoyez une erreur. ​
-  - Écrivez un programme similaire au précédent,​ à l'​exception qu'il prend la commande de la variable d'​environnement CMD. Un exemple d'​utilisation est //CMD=sub ./my-program 5 3//. +  - Écrivez un programme similaire au précédent,​ à l'​exception qu'il prend la commande de la variable d'​environnement CMD. Un exemple d'​utilisation est //CMD=mul cargo run 5 3//. //Hint: Utilisez [[https://​doc.rust-lang.org/​std/​env/​fn.var.html|env::​var()]] pour prendre la valeur de CMD//.
   - Écrivez un programme qui prend comme premier argument une commande suivie d'une liste de nombres. Les commandes peuvent être add, sub, mul, div, avg (moyenne), sort, unique. ​   - Écrivez un programme qui prend comme premier argument une commande suivie d'une liste de nombres. Les commandes peuvent être add, sub, mul, div, avg (moyenne), sort, unique. ​
-  - Modifiez le programme afin qu'il n'​exécute pas les commandes de la fonction principale, mais que chaque commande soit exécutée dans sa propre fonction. Ecrire des tests unitaires pour chacun d'eux. Les fonctions reçoivent comme arguments les entrées exactes de la ligne de commande (chaînes, pas de nombres). ​+  - Modifiez le programme afin qu'il n'​exécute pas les commandes de la fonction principale, mais que chaque commande soit exécutée dans sa propre fonction. Les fonctions reçoivent comme arguments les entrées exactes de la ligne de commande (chaînes, pas de nombres). ​ 
  
-===== Solutions ===== 
-[[https://​github.com/​UPB-FILS-SdE2/​Solutions/​tree/​main/​tp2|Solutions]] 
sde2/laboratoare/01_rust.1677952903.txt.gz · Last modified: 2023/03/04 20:01 by cristiana.andrei
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0