« Rust : Common collections » : différence entre les versions
Aller à la navigation
Aller à la recherche
Page créée avec « <nowiki> fn main() { // 1 - Vectors // Equivalent d'une liste en Python; // Un vector est une collection de valeurs du *même type* //Déclaration d'un vector de i32 vide let v: Vec<i32> = Vec::new(); //Déclaration avec des valeurs let v2 = vec![1, 2, 3, 4, 5]; //Update d'un vector mutable let mut v3 = Vec::new(); v3.push(5); v3.push(6); //Lecture //Via index, ici, pas de gestion d'erreur, cette méthode p... » |
Aucun résumé des modifications |
||
| Ligne 1 : | Ligne 1 : | ||
<syntaxhighlight lang='rust'> | |||
fn main() { | fn main() { | ||
// 1 - Vectors | // 1 - Vectors | ||
| Ligne 262 : | Ligne 262 : | ||
} | } | ||
</ | </syntaxhighlight> | ||
Dernière version du 3 novembre 2022 à 09:20
<syntaxhighlight lang='rust'> fn main() {
// 1 - Vectors // Equivalent d'une liste en Python; // Un vector est une collection de valeurs du *même type*
//Déclaration d'un vector de i32 vide let v: Vec<i32> = Vec::new();
//Déclaration avec des valeurs let v2 = vec![1, 2, 3, 4, 5];
//Update d'un vector mutable let mut v3 = Vec::new(); v3.push(5); v3.push(6);
//Lecture
//Via index, ici, pas de gestion d'erreur, cette méthode panique si
//on référence un élement non existant
let third: &i32 = &v2[2];
println!("3rd element is {}", third);
//Via get
//On utilise une option au cas où on ne récupère rien
//On a ainsi de la gestion d'erreur car cette méthode peut renvoyer None
let third: Option<&i32> = v2.get(2);
match third {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
//A se rappeller, on ne peut pas avoir un emprunt mutable //et un emprunt non mutable dans le même scope let mut v4 = vec![1, 2, 3];
let first = &v4[0];
//Ne fonctionnera pas //v.push(6);
//Itération
//non mutable
let v5 = vec![1, 2, 3, 69];
for i in &v {
println!("{}", i);
}
//mutable
//Ici on utilise * pour déréférencer i avant de le modifier.
//Ce n'est pas comme Python, donc !
let mut v6 = vec![100, 32, 57];
for i in &mut v6 {
*i += 50;
}
//Utiliser un enum pour stocker plusieurs types de variables
//On peut contourner le problème des types identiques au sein d'un Vector
//via un enum.
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
//Le vector a des méthodes : https://doc.rust-lang.org/std/vec/struct.Vec.html //Comme les autres structs, le vector est droppé quand on sort de son scope. //
//------------------------------------------------------------------------------
//2 - Strings //Un string est une collection de chars ! //Il est growable, mutable, owned, UTF-8 encoded //Il ne faut pas confondre String et str, aussi appellé "string litteral" ou slice (en fonction de la situation) //qui est juste une //collection de chars quelque part en mémoire, qui ne peut fonctionner qu'après emprunt (&str) //C'est un peu naze !
//Création
//Vide
let mut s = String::new();
//Depuis un litteral
//Plusieurs façons
let data = "Initial data";
let s = data.to_string();
let s = "Initial data".to_string();
let s = String::from("initial contents");
//UTF-8 permet plein de choses
let hello = String::from("السلام عليكم");
//Update
//push_str prend une slice en argument; on ne veut pas forcément s'approprier le contenu
let mut s = String::from("foo");
s.push_str("_bar");
//Exemple : ici, s2 ne fonctionnera pas si mon push sur s1 ne se fait pas via un emprunt
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
//Ne fonctionnera pas, push_str a pris la possession de s1
//println!("s2 is {}", s2);
//push() prend seulement un char
let mut s = String::from("Hello");
s.push('!');
//Concaténation
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used
//La fonction add (le + ici) a pour signature
//fn add(self, s: &str) -> String
//On voit que l'argument est un &str, ce que je n'ai pas utilisé au-dessus;
//mais le compilateur se démerde (pour une fois) et transforme mon &s2 en &s2[..]
//En réalité add prend possession de s1 et lui colle le contenu de s2 à la fin
//De toute façon, on peut préférer utiliser !format qui est plus clair
//Et utilise implicitement des références
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
println!("{s2}");
//Index
//On ne peut pas utiliser d'index sur un string:
let s1 = String::from("hello");
//Nope...
//let h = s1[0];
//En réalité, un string est un wrapper fonctionnant sur un Vector<u8>.
//Les code points unicode ne font pas tous la même taille : une lettre latine prend 1 octet,
//une lettre cyrillique en prend 2 par exemple. Du coup, dans ma collection de u8, je ne sais pas lesquels
//correspondent à une lettre... Donc, pas d'index.
//En plus, on peut représenter un string unicode en tant que vector de u8, ensemble de valeurs
//scalaire unicodes (qui peuvent être des diacritiques par exemples, et donc pas vraiment des
//lettres) et en tant que clusters de graphemes, soit les lettres avec les diacritiques
//appliqués.
//
//Il est donc important de savoir si on opère sur les octets du string ou ses caractères !
//
//Hé ben merde alors !
//Slicing //Plutôt que d'indexer, on peut faire des slices... let hello = "Здравствуйте"; let s = &hello[0..4]; //s contiendra les 4 premier *octets* (et pas forcément lettres, donc) //Si je coupe au milieu d'un charactère, ça plante ! //s = &hello[0..1]
//Iterer
//On peut itérer sur les caractères (ouf)
//Même si ça ne marche pas forcément sur des charactères complexes comme
//avec des diacritiques
for c in "Зд".chars() {
println!("{}", c);
}
//Ou sur les octets
for b in "Зд".bytes() {
println!("{}", b);
}
//Nous affichera des chiffres
//
//Pour citer la doc : Strings Are Not So Simple. On doit appréhender la complexité, mais
//en échange on a pas d'erreurs sur des caractères chiants
//--------------------------------------------------------------------------------------- // //3 - hash maps //Equivalent d'un dictionnaire en Python : HashMap<K, V> //Se base sur un algorithme de hashage pour relier clef et valeur //Rust utilise SipHash (https://en.wikipedia.org/wiki/SipHash) qui résiste aux attaque DOS //utilisant des tables de hashage //Ce n'est pas le plus rapide mais il est safe; cela dit on peut changer //Checker la lib standard pour les méthodes ! Attention, la hashmap n'est pas incluse par //défaut.
//Création //Avec insertion use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
//Accès aux valeurs : utiliser get
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
//Get renvoie une Option<&V>, on peut se récupérer un None.
//Ici on utilise copied() pour récupérer un <i32> au lieu d'un <&i32>
//et unwrap_or(0) pour avoir soit la valeur, soit 0
//Itération
for (key, value) in &scores {
println!("{}: {}", key, value);
}
//Ownership
//Quand une hashmap récupère une valeur, 2 possibilités:
//* Soit la valeur a le trait copy (comme i32) et alors elle est copiée
//* Soit elle ne l'as pas (comme String) et alors elle est réapropriée
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new(); map.insert(field_name, field_value); // field_name and field_value are invalid at this point, try using them and // see what compiler error you get! (Value borrowed after move) //On peut insérer des références, mais il faut alors s'assurer que les //items référencés sont valides (lifetime)
//Update //Si je réinsère une valeur sur une clef existante, elle est remplacée, bien sûr. let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
//Je peux choisir d'ajouter une clef - valeur seulement si la clef n'existe pas
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
//...ou en se basant sur une valeur déjà existante
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
} </syntaxhighlight>