Introduction à Rust: variables et types

Choose a study mode

Play Quiz
Study Flashcards
Spaced Repetition
Chat to Lesson

Podcast

Play an AI-generated podcast conversation about this lesson
Download our mobile app to listen on the go
Get App

Questions and Answers

Quelle est la principale différence entre l'utilisation de &impl Trait et &dyn Trait dans la définition de fonctions génériques en Rust ?

  • `&impl Trait` requiert que le type implémente le trait `Sized`, alors que `&dyn Trait` fonctionne avec des types non `Sized`.
  • `&impl Trait` ne permet pas l'utilisation de méthodes par défaut définies dans le trait, contrairement à `&dyn Trait`.
  • `&impl Trait` ne peut être utilisé qu'avec des types de données primitifs, tandis que `&dyn Trait` est nécessaire pour les structures et les enums complexes.
  • `&impl Trait` permet la création de versions multiples de la fonction au moment de la compilation, tandis que `&dyn Trait` utilise une table dynamique virtuelle (vtable) pour déterminer le type à l'exécution. (correct)

Dans quel contexte l'inférence de type en Rust peut-elle échouer, nécessitant une annotation de type explicite ?

  • Lorsque le type d'une variable est immédiatement évident à partir de sa valeur littérale.
  • Lors de la définition de constantes globales avec des valeurs calculées à la compilation.
  • Lorsqu'une variable est utilisée dans une boucle `for` avec un itérateur typé.
  • Lorsqu'une fonction générique est appelée sans que le type des paramètres puisse être déduit des arguments. (correct)

Comment la gestion de la mémoire par défaut en Rust, avec son système d'ownership, affecte-t-elle l'utilisation de structures de données auto-référentielles ?

  • La création de structures auto-référentielles nécessite l'utilisation de `Pin` et des types comme `Box` ou `Rc` pour garantir que les références restent valides pendant toute la durée de vie de la structure. (correct)
  • Les structures auto-référentielles nécessitent l'utilisation de pointeurs bruts (`unsafe`) pour contourner les vérifications du compilateur.
  • Les structures auto-référentielles sont naturellement compatibles avec le système d'ownership de Rust et ne nécessitent aucune précaution particulière.
  • L'ownership en Rust interdit l'utilisation de structures auto-référentielles, car elles mèneraient inévitablement à des références invalides.

Quelle est l'implication de l'implémentation du trait Drop pour une structure en Rust concernant la gestion des ressources?

<p>Le trait <code>Drop</code> permet de définir un comportement personnalisé lors de la désallocation de la mémoire occupée par une structure, mais son exécution n'est pas garantie en cas de panique. (C)</p>
Signup and view all the answers

Comment Rust gère-t-il la concurrence des données pour prévenir les data races, et quelles sont les structures de données concurrentes couramment utilisées pour faciliter cette gestion ?

<p>Rust s'appuie sur le système de types pour interdire les accès mutables concurrents, en utilisant des types comme <code>Mutex</code> et <code>RwLock</code> pour gérer l'accès aux données partagées. (A)</p>
Signup and view all the answers

Dans le contexte des macros en Rust, quelle est la différence fondamentale entre les macros déclaratives (macros macro_rules!) et les macros procédurales (procedural macros) ?

<p>Les macros déclaratives sont définies en utilisant un système de correspondance de motifs (pattern matching), tandis que les macros procédurales sont définies en utilisant du code Rust complet qui manipule l'Abstract Syntax Tree (AST). (C)</p>
Signup and view all the answers

Comment l'utilisation de Cell et RefCell permet-elle de contourner les règles d'emprunt de Rust, et dans quels scénarios leur utilisation est-elle justifiée ?

<p><code>Cell</code> et <code>RefCell</code> permettent une mutabilité intérieure, contournant ainsi les règles d'emprunt au moment de la compilation, mais avec des vérifications au moment de l'exécution, et sont justifiés dans les cas où la vérification statique est impossible ou trop complexe. (A)</p>
Signup and view all the answers

Quelle est la différence fondamentale entre un trait object et un type générique contraint par un trait en Rust, et quand choisir l'un plutôt que l'autre ?

<p>Un <code>trait object</code> permet d'utiliser des types différents implémentant le même trait dans une collection, avec un coût de dispatch dynamique, tandis qu'un type générique offre une performance statique mais nécessite de connaître le type exact au moment de la compilation. (D)</p>
Signup and view all the answers

Comment fonctionne le système de lifetimes en Rust, et quel problème spécifique cherche-t-il à résoudre concernant la sécurité de la mémoire ?

<p>Le système de lifetimes en Rust garantit que toutes les références pointent vers des données valides pendant toute leur durée de vie, évitant ainsi les dangling pointers et les accès à la mémoire invalide. (A)</p>
Signup and view all the answers

Quelle est la principale utilité des traits From et Into en Rust, et comment contribuent-ils à l'écriture de code plus propre et plus maintenable ?

<p><code>From</code> et <code>Into</code> permettent de définir des conversions de types simples et sans perte, facilitant ainsi la conversion entre différents types de données avec un minimum de code boilerplate. (C)</p>
Signup and view all the answers

Dans quel scénario l'utilisation de Box<T> est-elle indispensable en Rust, et quels problèmes spécifiques résout-elle liés à la taille des types et à l'ownership ?

<p><code>Box&lt;T&gt;</code> est indispensable pour créer des structures de données récursives, car il permet de donner une taille fixe à un type qui, autrement, serait de taille infinie, et il gère l'ownership des données allouées sur le heap. (C)</p>
Signup and view all the answers

Comment le trait Deref permet-il de simuler l'héritage en Rust, et quelles sont les limites de cette approche comparée à l'héritage traditionnel dans d'autres langages ?

<p><code>Deref</code> permet à une structure de se comporter comme une autre structure, en donnant accès à ses méthodes, mais sans hériter de sa structure interne ni permettre de substitution polymorphe. (D)</p>
Signup and view all the answers

Quelle est la différence entre String et &str en Rust, et quand devriez-vous utiliser l'un plutôt que l'autre pour optimiser la performance et la flexibilité de votre code ?

<p><code>String</code> est une chaîne de caractères allouée sur le heap, offrant la possibilité de modifier la chaîne, tandis que <code>&amp;str</code> est une vue (slice) immuable sur une chaîne, qui peut être allouée statiquement ou sur le heap. (C)</p>
Signup and view all the answers

Comment les traits en Rust permettent-ils de mettre en œuvre le polymorphisme statique et dynamique, et quels sont les avantages et inconvénients de chaque approche ?

<p>Les traits permettent le polymorphisme statique via les generics, offrant une performance optimale, et le polymorphisme dynamique via les trait objects, offrant une flexibilité accrue au prix d'un coût d'exécution plus élevé. (C)</p>
Signup and view all the answers

Quelle est la signification du mot-clé unsafe en Rust, et dans quelles situations spécifiques son utilisation est-elle nécessaire pour interagir avec des fonctionnalités de bas niveau ?

<p><code>unsafe</code> permet d'effectuer des opérations qui ne peuvent pas être vérifiées par le compilateur Rust pour garantir la sécurité de la mémoire, comme l'accès direct à la mémoire via des pointeurs bruts, nécessitant une attention particulière du développeur. (A)</p>
Signup and view all the answers

Comment Rust utilise-t-il les enums avec des données associées (tagged unions) pour représenter des états ou des résultats possibles, et quels avantages cela offre-t-il en termes de sécurité et d'expressivité du code ?

<p>Les enums avec des données associées permettent de représenter différents états ou résultats possibles de manière sûre et expressive, en garantissant que seules les opérations valides pour chaque état peuvent être effectuées. (A)</p>
Signup and view all the answers

Comment la sémantique de move en Rust affecte-t-elle la gestion de la mémoire et la durée de vie des variables, et quels sont les mécanismes pour éviter les erreurs liées à la perte de ownership ?

<p>La sémantique de move en Rust transfère l'ownership des données d'une variable à une autre, invalidant la variable d'origine, ce qui peut entraîner des erreurs si l'on tente d'accéder à la variable invalidée. Pour éviter ces erreurs, on peut utiliser le borrowing ou le cloning. (A)</p>
Signup and view all the answers

Comment Rust gère-t-il les erreurs, et quelle est la différence entre l'utilisation de panic! et du type Result<T, E> pour la gestion des erreurs récupérables et non récupérables ?

<p><code>panic!</code> est utilisé pour les erreurs non récupérables, indiquant un état irrécupérable du programme, tandis que <code>Result&lt;T, E&gt;</code> est utilisé pour les erreurs récupérables, permettant de propager ou de traiter l'erreur de manière contrôlée. (C)</p>
Signup and view all the answers

Quelles sont les principales différences entre les pointeurs bruts (*const T et *mut T) et les références (&T et &mut T) en Rust, et dans quel contexte l'utilisation des pointeurs bruts est-elle justifiée malgré les risques potentiels ?

<p>Les pointeurs bruts ne sont pas vérifiés par le compilateur et nécessitent l'utilisation du mot-clé <code>unsafe</code> pour être déréférencés, offrant ainsi une flexibilité accrue pour interagir avec du code de bas niveau ou des systèmes externes, mais au prix d'une responsabilité accrue en matière de sécurité mémoire. (D)</p>
Signup and view all the answers

Comment la gestion de la mémoire en Rust, basée sur l'ownership et le borrowing, contribue-t-elle à prévenir les problèmes de concurrence tels que les data races et les deadlocks, et quelles sont les structures de données concurrentes couramment utilisées pour faciliter cette gestion ?

<p>Rust s'appuie sur son système d'ownership et de borrowing pour interdire statiquement les data races, et offre des structures de données concurrentes comme <code>Mutex</code>, <code>RwLock</code> et les channels pour gérer les accès concurrents de manière sûre et efficace. (A)</p>
Signup and view all the answers

Flashcards

Fonction main

Fonction principale en Rust.

mut

Déclare une variable mutable.

i8, i16, i32, i64, i128, isize

Types d'entiers signés.

u8, u16, u32, u64, u128, usize

Types d'entiers non signés.

Signup and view all the flashcards

f32, f64

Types de nombres à virgule flottante.

Signup and view all the flashcards

char

Valeurs scalaires Unicode.

Signup and view all the flashcards

bool

Type de données booléen.

Signup and view all the flashcards

const

Déclarer une constante.

Signup and view all the flashcards

fn nom_fonction()

Définition d'une fonction en Rust.

Signup and view all the flashcards

if, else if, else

Conditions logiques.

Signup and view all the flashcards

while

Boucle de répétition.

Signup and view all the flashcards

break

Arrête une boucle.

Signup and view all the flashcards

continue

Passe à l'itération suivante.

Signup and view all the flashcards

macro!

Déclaration d'une macro.

Signup and view all the flashcards

Vec

Créer une liste.

Signup and view all the flashcards

Tuple

Créer un tuple.

Signup and view all the flashcards

&

Référence partagée (lecture seule).

Signup and view all the flashcards

&mut

Référence exclusive (mutable).

Signup and view all the flashcards

Slices

Pointeur vers une section d'une collection.

Signup and view all the flashcards

Struct

Type de données structurées.

Signup and view all the flashcards

Study Notes

Généralités sur Rust

Fonction main

  • La fonction main est le point d'entrée du programme.
fn main() {
    // Votre code ici
}

Variables

  • Les variables sont déclarées avec le mot-clé let.
  • Pour rendre une variable mutable, on utilise mut.
let mut nom_variable: type = valeur;
  • Le mot-clé mut est requis pour pouvoir modifier la variable après son initialisation.

Types de données

  • Rust est fortement typé, mais permet l'inférence de type. Il prend en charge plusieurs types de données primitifs:
    • Entiers signés : i8, i16, i32, i64, i128, isize
    • Entiers non signés : u8, u16, u32, u64, u128, usize
    • Nombres à virgule flottante : f32, f64
    • Scalaires Unicode : char
    • Booléens : bool
  • Exemples de littéraux pour chaque type:
    • Entiers signés : -10, 0, 1_000, 123_i64
    • Entiers non signés : 0, 123, 10_u16
    • Nombres à virgule flottante : 3.14, -10.0e20, 2_f32
    • char : 'a', 'α', '∞'
    • Booléens : true, false
  • Les types iN, uN et fN ont une largeur de N bits.
  • isize et usize correspondent à la largeur d'un pointeur.
  • Le type char est codé sur 32 bits.
  • Le type bool est codé sur 8 bits.
  • L'inférence de type permet d'omettre la déclaration du type d'une variable.
  • Le compilateur détermine le type en fonction de la première affectation ou utilisation.

Constantes

  • Le mot-clé const peut être utilisé à la place de let pour déclarer une constante.

Fonctions

  • Les fonctions sont déclarées avec le mot-clé fn.
fn nom_fonction(parameter1: type, ..., parameterN: type) -> typeRetour {
    contenu
}
  • La valeur de retour est la dernière expression évaluée dans la fonction.

Blocs de code

  • Un bloc de code est délimité par des accolades {}.
  • La valeur d'un bloc est la dernière valeur à la fin du bloc.
  • Si un bloc se termine par un point-virgule ;, sa valeur est ().

Opérateurs logiques

  • Opérateur if :
if predicat { 
    // Si ... faire 
}
  • Opérateur else if :
else if predicat { 
    // Sinon si ... faire
}
  • Opérateur else :
else {
    // Sinon faire
}
  • Opérateur if let : permet de tester si une variable correspond à un certain modèle.
if let Ok(duration) = Duration::try_from_secs_f32(secs) {
    // ...
}

Correspondance de motifs (Matching)

  • L'opérateur match est équivalent à switch.
match nom_variable {
    Value1 => block1,
    Value2 => block2,
    Value3 => block3,
    _ => blockDefault,
}
  • Des opérateurs/conditions peuvent être ajoutés aux valeurs.
Value1 | value2 && value3 => block4
Value if predicate sur value => block5
  • L'opérateur match peut être combiné avec des structures ou des enums pour tester certains attributs.
match nom_struct {
    typeStruct { attribute1: value1, attribute2: value2, ..., attributeN: valueN } => block1,
    typeStruct { attribute1: nomVar } => block2,
    typeStruct { attribute1, attribute2, .. } => block3,
}
  • Pour les enums:
typeEnum::attribute(value) => block
  • Un nom de variable peut être utilisé à la place de value pour tester et utiliser la valeur de l'attribut.

Boucles

  • Boucle while :
while predicat {
    // Tant que ... faire
}
  • Variante avec if let while let.
  • Boucle for :
for name/value_element in collection {
    // Pour chaque element dans ..., de ... à ..., faire
}
  • Boucle infinie loop :
loop {
    // Répéter indéfiniment
}
  • continue permet de passer directement à l'itération suivante dans une boucle.
  • break quitte instantanément une boucle.

Macros

  • Les macros sont des fonctions pouvant accepter un nombre indéfini de paramètres.
nomMacro!(param1, param2, ..., paramN);

Collections

  • Liste (vecteur) :
Let mut nomVar : [ type ; tailleListe ] = [ value1,... value_tailleListe ]
                                     = [ valueForNumber ; number]
  • Pour modifier une valeur à un index donné :
nomVar[n] = ...
  • Itération dans une liste : élément in nomListe
  • Tuple : ensemble ordonné de valeurs de types potentiellement différents.
Let nomTuple= ( typeValeur1 , ..., typeValeurN )= ( valeur1 , ..., valeur n )
  • Association des éléments d'un tuple à des variables :
let (var1, ..., varN) = tuple;
  • Ignorer des valeurs dans un tuple :
let (var1, _, var3, …, varN) = tuple;
  • Ignorer le début ou la fin d'un tuple :
let (.., varN-1, VarN) = tuple

Références

  • Référence partagée (lecture seule) :
                 let mut nomRef: &type_var_a_referer = &nomVariable ;
- nomRef
  • Permet de récupérer la valeur de la variable référencée.
  • Référence exclusive (mutable) :
let nomRef = &mut var
  • Permet de modifier la valeur de la variable.
  • Une seule référence exclusive par variable est autorisée.

Slices

  • Un slice est un pointeur vers une portion contiguë d'une collection.
Let slide: &[type_collection] = &collection [i.. n];
  • Pointeur vers les éléments de la collection d’indice k sur l’intervalle [i, n-1]
  • Le type &str est un slice de bytes encodés en UTF-8 (&[u8]).
  • Le type String est similaire à un Vec avec T = u8.

Structures (Structs)

  • Déclaration d'une structure :
struct Struct_name {
                 attribute1 : type1 ;
                 attribute2 : type2 ;
      } ;
  • Récupérer un attribut : Struct_Name.attribute
  • Créer un objet d'une structure :
let mut var_name : struct_name{ attribute_1 : value, … , attribute_n : value }
  • Implémentation de méthodes pour une structure :
impl nomStruct {
                 fn nomFunc(self parameter1 : type ,…, parameterN : type )->typeRetour{}
                 //&self : ne permet pas de modifier la struct (shared read only).
                 //&mut self : modifier son contenu (exclusive read/write)
       }
  • Accéder aux attributs dans une méthode : self.attribute
  • Définir un constructeur (méthode new) :
fn new ( parameter 1 : type1,… ) -> Self{
                 …
                 Self {attribute1 : value, …, attributeN : valueN }
                 //On doit donner une valeur à chaque attribut
           }
  • Attention : Toujours finir la fonction par Self{…} pour retourner la structure.

TupleStruct

  • Structures avec des attributs sans noms :
struct struct_name (type1,…,typeN);
  • Récupérer un attribut : struct_name.k (k est l'indice de l'attribut, de 0 à n-1)

Traits

  • Permet d'ajouter des interfaces implémentables par des structs :
trait nomTrait {
                fn abstractFunc(&self,…) -> typeReturn;
      }
  • La méthode de nomTrait est alors abstraite et doit être implémenté par une structure pour l’utiliser :
impl nomTrait for nomStruct{
          fn abstractFunc(&self,…) -> typeReturn {…}
      }
  • Héritage avec des Traits :
trait nomTrait : superTrait {…}
  • Associer des types à un trait :
trait nomTrait {
            type typeReturn ;
            fn abstractFunc(&self,…) -> typeReturn;
      }
       impl nomTrait for nomStruct{
           type typeReturn = type ;
           fn abstractFunc(&self,…) -> typeReturn {…}
      }

Autres caractéristiques des traits

  • Certains traits supportés par le langage :
#[derive(trait1, …, traitN)]
Struct nomStruct {}

Enums

  • Type dont les valeurs possibles sont limitées et définies au moment de la création :
enum name {
                             value1,
                             …,
                             valueN,
                  } ;
  • Utilisation : Enum_name ::value_k
  • Permet de donner la valeur numéro k d’une énumération à une variable de ce type.

Aliases

  • Déclarer un nouveau nom de type :
type name_type_1 = name_type_2

Fonctions génériques

  • Implémenter des fonctions avec des types génériques (patrons, templates) :
fn nomfunc<T> (param1 :type1 ,…, paramk : T,…, paramN :typeN) -> T {}
  • Les paramètres de type T doivent avoir un type implémentant T (voir struct pour implémentation/trait)
  • Déclarer des structures implémentant des types génériques :
struct Struct_name <T> {
            attribute1 : T ;
            …
      } ;

Fonctions génériques et dynamiques

  • Les fonctions génériques et dynamiques permettent d’utiliser les comportements (méthodes) des types/struct implémentant le type d’un paramètre en entrée.
fn generic (attribut1: &impl typeA)
           …
}
  • &impl permet qu’à la compilation, Rust créer une version de la fonction pour chaque type implémentant typeA .
fn generic (attribut1: &dyn typeA)
                 …
}
  • &dyn ne créer pas différentes versions de la méthode, mais recherche dynamiquement le bon type dans une vtable contenant l’ensemble des types implémentant typeA.
  • Attention, la variable passée en paramètre doit être un pointeur.

Documentation et commentaires

  • Syntaxe des commentaires :
    • /// commentaire (commentaire de documentation)
    • //! Inner doc comment (commentaire de documentation interne)
  • Inner doc comment sert à documenter un élément à l'intérieur d'un block, d'une structure ou d'une fonction.

Standard Library

  • La Standard Library est documentée et publiée sur docs.rs (outil rustdoc).
  • Ressource supplémentaire :
    • https://google.github.io/comprehensive-rust/std-traits.html
    • https://google.github.io/comprehensive-rust/std-types.html

Option

  • Permet de stocker une valeur qui peut être présente ou absente.
let mut var1: Option<type> = var2;
  • Méthodes :
  • unwrap() : Récupère la valeur si elle est présente, panique sinon.
  • expect(« message ») : Comme unwrap(), mais avec un message d'erreur personnalisé.

Résultat

  • Permet de stocker le résultat d'une opération et d'indiquer si elle a réussi ou échoué :
Result<TypeValeurRetourné, TypeErreur> = operation(…)
storedResult = Result<TypeValeurRetourné, TypeErreur>= operation(…)
match storedResult{
    Ok(mut storedResult) => {…}
    Err(err) => {…}
}

String

  • Liste de caractères encodés en UTF-8.
  • Méthodes :
    • String::new() : Crée une nouvelle chaîne vide.
    • push_str(string) : Ajoute une autre string à la fin.
    • push(« c ») : Ajoute un caractère.
    • len() : Retourne la taille de la chaîne.
    • count() : Retourne le nombre de caractères.
    • capacity() : Retourne le nombre d’éléments max de la chaîne.

Vecteurs

  • Permet de créer des tableaux dynamiques.
  • Méthodes :
    • Vec::new() : Crée un nouveau vecteur vide.
    • push(element) : Ajoute un element après le dernier
    • len : nombre d'élément
    • capacity : nombre max d'éléments
    • retain( condition ) : Conserve uniquement les éléments qui respectent la condition.
    • dedup() : Supprime les éléments en double.

HashMap

  • Dictionnaire : associe une valeur à une clé
  • Méthodes :
    • HashMap::new() : Crée un nouveau dictionnaire vide.
    • insert( Stringkey , Intvalue ) : Insère une nouvelle donnée dans le dictionnaire.
    • containskey( key ) : Retourne vrai si le dictionnaire contient la clé.
    • len() : Retourne le nombre de clés dans le dictionnaire.
    • get( key ) : Récupère la valeur associée à la clé.

Comparaisons

  • Définir une relation d'égalité (== ou !=) pour des structures :
impl PartialEq for typename{
            fn eq(&self, other: &Self) -> bool {`
                self.attribute == other.attribute
            }
            fn ne(&self, other: &Self) -> bool {
                self.attribute != other.attribute
            }
    }

Operators

  • implémentation des opérateurs pour les structs :
impl std::ops::Add for typename {
            type Output = Self; fn add(self, other: Self) -> Self {
                        Self { attr1: self.attr1 + other. attr1, attr2: self. attr2 +  other. attr2 }
            }
}

Conversion de types

  • from(): Extrait une valeur d’un type vers une valeur d’un autre type.
let one = i16::from(true);
  • into(): Conversion d'une valeur d'un type vers un autre type.
let one: i16 = true.into();
  • as: Utiliser une variable comme une variable d’un autre type.
var as type

Lecture et écriture de données

  • Read et BufRead permettent d'implémenter des fonctions de lecture de données (fichiers, chaînes, etc.) en tant que flux d'octets (u8).
fn reading<R: Read>(reader: R) …{
     let buf_reader = BufReader::new(reader);…
}
  • reader est le contenu à lire et buf_reader est le lecteur.
  • Write permet d'implémenter des fonctions d'écriture..
fn writeSomething(writer: &mut W, toWrite: &str) ->…{
            writer.write_all(toWrite.as_bytes());…

}

Default

  •  Implémenter une valeur par défaut à un type :
impl Default for type1 {               
    fn default() -> type1{ valAttr1, valAttr2,… valAttrN }
}
  • Utiliser les valeurs par défaut : nomType ::default()

Mémoire

  • Allocation mémoire
  • Allocation mémoire dans le Stack (pile):
    • Valable pour les variables locales
    • Valable pour les tailles connues à la compilation -Très efficace car pointeur -Permet facilement un accès rapide aux zones mémoires souvent utilisés (cache mémoire)
  • Allocation mémoire dans le Heap (tas -Valable pour le stockage en dehors des appels de fonctions -Valable pour les tailles dynamiques -Moins efficace que la pile -Pas de garantie d'accès rapide

Ownership

  • Chaque variable dans un code possède une valeur dont elle est propriétaire, et un scope.
  • Chaque valeur ne peut avoir qu’un seul propriétaire.
  • Quand le scope arrive à sa fin, alors la variable est désallouée et sa valeur est supprimée de la mémoire.
  • Lors d’un assignement par =, alors la variable initiale perd sa valeur et la nouvelle devient propriétaire de la valeur.
  • Pour copier la valeur d’une variable sans qu’elle perde sa valeur, on utilise la fonction clone : var2(var1.clone()) ;
  • Si un type implémente le trait copy, alors l’affectation deviendra une copie.

Pointeurs

  • Box est un pointeur vers une valeur du heap :
let var 1 = Box::new(value) ;
Box<T> implémente le trait Deref
let varBoxStruct = Box ::new( valueStruct )
varBoxStruct::methodStruct()
  • Rc : pointeur partagé. Pointeur vers une valeur et un compteur représentant le nombre de variables ayant accès au pointeur :
let var1 = Rc::new(value);
let var2 = Rc::clone(&var1);

Emprunt (Borrowing)

  • Au lieu de passer directement une variable en paramètre de fonction (car l'assignement supprime la valeur initiale), on passe une copie de la valeur:
fn func(val1: &type1, val2: &type2) -> … {
                …
            }
let var1 = value1 ;
let var2 = value1 ;
func ( &var1, &var2 )
  • Contraintes sur les emprunts de valeurs :
  • On ne peut emprunter qu’une valeur appartenant au même scope
  • Aliasing rule : on ne peut avoir qu’une référence exclusive en écriture en même temps

Cell/RefCell

  • Cell: Permet de créer un pointeur avec un getter/setter sur la variable qu'il contient.
let cell = Cell::new(value);
cell.set(value);
dbg!(cell.get());
  • CellRef: Permet d'emprunter sa valeur dans une autre variable, pour avoir une référence exclusive.
let cell = RefCell::new(value);
let mut cell_ref = cell.borrow_mut();
- cell_ref = value

Durées de vie (Lifetimes)

  • Toute référence possède une durée de vie devant être inférieure à la durée de vie (scope) de la variable.
fn func <'a> (var1: &'a type1) -> &'a type1
  • Ici, on dit que la durée de vie de la référence retournée à la même durée de vie que celle passée en entrée (var1).

Studying That Suits You

Use AI to generate personalized quizzes and flashcards to suit your learning preferences.

Quiz Team

Related Documents

More Like This

Rust Programming Basics Quiz
10 questions

Rust Programming Basics Quiz

UnmatchedJadeite2405 avatar
UnmatchedJadeite2405
Concepts de base de Rust
38 questions

Concepts de base de Rust

ImportantJasper9535 avatar
ImportantJasper9535
Concepts de base de Rust
45 questions

Concepts de base de Rust

CleanestBananaTree avatar
CleanestBananaTree
Introduction à Rust
20 questions

Introduction à Rust

AdventuresomeDravite avatar
AdventuresomeDravite
Use Quizgecko on...
Browser
Browser