Environnement de travail¶
Sur votre machine perso, il est conseillé d'installer rust avec rustup et d'utiliser vscode pour éditer le code. Il y a une extension vscode
appellée rust-analyzer
qui est très bien.
Sur les machines du département, recopiez le script /usr/local/Rust/var-env.sh
à la fin de votre .profile
pour configurer cargo
et rustc
, puis
installez l'extension rust-analyzer
dans vscode.
En dépannage, si rien ne marche, vous pouvez travailler avec Rust Playground.
Exercice 1¶
- Créez un répertoire
TPs-Paradigmes-2
et un sous répertoireTP1
, puis créez un projethello_world
dansTP1
avec la commandecargo
. Exécutez votre programme. - En vous aidant du Rust book Chapitre 12.1, modifiez votre programme pour qu'il prenne en argument de ligne de commande un nom, et affiche
"hello, {nom}!"
plutôt que "hello, world!". Indication: vous pourrez utiliser la méthode collect des itérateurs pour obtenir unVec
contenant tous les arguments de la ligne de commande. - Que se passe-t-il si vous lancez le programme sans fournir le nom en argument? Générez un message d'erreur plus explicite avec
panic!
. - On veut maintenant ajouter une option
-g
à ce petit programme. Lorsque l'option est activée, le tableau des arguments de la ligne de commande est affiché sur la sortie d'erreur avec la macrodbg!
. Ensuite, on le programme affiche "hello {nom}" pour chaque nom apparaissant sur la ligne de commande, cf exemples ci-dessous
cargo run
[pas d'affichage]
cargo run alice bob
bonjour, alice!
bonjour, bob!
cargo run alice -g bob
[src/main.rs:25:9] &args = [
"target/debug/hello_world",
"alice",
"-g",
"bob",
]
bonjour, alice!
bonjour, bob!
Exercice 2¶
- Écrivez une fonction:
fn concat(v1: Vec<i32>, v2: Vec<i32>) -> Vec<i32>
qui renvoie la concaténation dev1
etv2
. - Écrivez une fonction
concat2
similaire àconcat
sauf que ses paramètres sont empruntés, etv1
est modifié en place. - Pourquoi n'est-il pas possible d'écrire une fonction
fn dup<T>(x: T) -> (T, T)
? Pour quels typesT
est-ce possible? - Même question pour
fn return_dangling_ptr<'a, T>(x: T) -> &'a T
(rappel: les paramètres de fonction sont stockés dans la pile). Écrivez la fonctionreturn_dangling_ptr
en C, et regardez ce que ditgcc
. - Écrivez une fonction
fn push_ampersand<T>(v: &Vec<T>) -> Vec<&T>
- Écrivez une fonction
fn concat3<T>(v1: &Vec<T>, v2: &Vec<T>) -> Vec<&T>
(en ajoutant les annotations de durées de vies nécessaires).
Exercice 3¶
- Créez un nouveau projet
exo3
. Dansmain.rs
, déclarez un typeMoney
correspondant à un enregistrement avec deux champs:
cents
qui est un entier non signé de la taille d'un mot machinecurrency
qui est une chaîne de caractères
- Implémentez une méthode
to_string()
pourMoney
(indication: utilisez la macroformat!
, similaire àprint!
, cf doc complète). On aura par exemple
let m = Money { cents: 3703, currency: "$".to_string() }
let s = m.to_string() // "37,03 $"
Testez votre code en modifiant la fonction main
pour qu'elle affiche la variable s
définie ci-dessus.
- Insérez le test ci-dessous dans
main.rs
, et vérifiez qu'il passe. Vous pouvez soit lancer le test depuis vscode, soit en ligne de commande aveccargo test test_money_to_string
(voir documentation).
#[cfg(test)]
mod tests {
#[test]
fn test_money_to_string() {
let m = Money { cents: 3703, currency: "$".to_string() }
let s = m.to_string() // "37,03 $"
assert_eq!(s, "37,43 $");
}
}
- Écrivez une fonction
convert
à trois arguments:
- une valeur de type
Argent
- une monnaie représentée par une chaîne de caractères ("$", "€", "£", "¥", etc)
- une liste associative qui donne la valeur d'un dollars dans chacune des monnaies listées, par exemple
vec![(0.93, "€"), (0.79,"£"),(150.0,"¥")]
La fonction modifie son premier argument en place: elle remplace le champscurrency
par le second argument de la fonction, et met à jour le champscents
selon les taux de conversion passés en troisième argument. Vous utiliserez le dollars comme monnaie pivot, il faudra donc en général d'abord convertir en dollars puis dans la monnaie souhaitée.
Écrivez une fonction
convert_h
identique à celle de la question précèdente, sauf que son troisième argument est unHashMap
.Écrivez une méthode
withdraw(&mut self, amount: &Argent, rates: HashMap<String,fsize>) -> Result<(),Argent>
dans un blocimpl Argent
. La méthode a pour effet de déduire deself.cents
, lorsque c'est possible, la quantitée représentée paramount
, une fois celle-ci convertie à la même unité queself
; la méthode ne modifie pas le champscurrency
deself
. La méthode utilisera la fonctionconvert_h
de la fonction précédente sur l'argumentamount
, qu'il vous faudra cloner (pourquoi?). Par exemple, sans se préoccuper de la conversion de monnaie:- en supposant que self vaut initialement 100 € et amount vaut 10 €, la méthode met self à 90 € et termine sans erreur.
- en supposant que self vaut initialement 100 € et amount vaut 1000 € , la méthode laisse self intact et termine avec une erreur qui contient la valeur
1000 €.
[Très facile] Écrivez une méthode
repeat_withdraw(&mut self, amounts: &Vec<Argent>, rates: &HashMap<String,fsize>) -> Result<(),Argent>
qui appelle withdraw successivement sur chacun des montants de la listeamounts
, tant qu'il est possible de retirer. Vous utiliserez?
.