Rouille - Pointeurs intelligents

Rust alloue tout sur la pile par défaut. Vous pouvez stocker des éléments sur le tas en les enveloppant dans des pointeurs intelligents comme Box . Des types tels que Vec et String aident implicitement l'allocation de tas. Les pointeurs intelligents implémentent les traits répertoriés dans le tableau ci-dessous. Ces traits des pointeurs intelligents les différencient d'une structure ordinaire -

Sr. Non Nom du trait Paquet et description
1 Deref

std::ops::Deref

Utilisé pour les opérations de déréférencement immuables, comme * v.

2 Laissez tomber

std::ops::Drop

Utilisé pour exécuter du code lorsqu'une valeur est hors de portée. Ceci est parfois appelé un destructeur

Dans ce chapitre, nous découvrirons les Boxpointeur intelligent. Nous allons également apprendre à créer un pointeur intelligent personnalisé comme Box.

Boîte

Le pointeur intelligent Box, également appelé boîte, vous permet de stocker des données sur le tas plutôt que sur la pile. La pile contient le pointeur vers les données du tas. Une boîte n'a pas de surcharge de performances, autre que le stockage de leurs données sur le tas.

Voyons comment utiliser une boîte pour stocker une valeur i32 sur le tas.

fn main() {
   let var_i32 = 5; 
   //stack
   let b = Box::new(var_i32); 
   //heap
   println!("b = {}", b);
}

Production

b = 5

Pour accéder à une valeur pointée par une variable, utilisez le déréférencement. Le * est utilisé comme opérateur de déréférencement. Voyons comment utiliser le déréférencement avec Box.

fn main() {
   let x = 5; 
   //value type variable
   let y = Box::new(x); 
   //y points to a new value 5 in the heap

   println!("{}",5==x);
   println!("{}",5==*y); 
   //dereferencing y
}

La variable x est un type valeur avec la valeur 5. Ainsi, l'expression 5 == x retournera true. La variable y pointe vers le tas. Pour accéder à la valeur dans le tas, nous devons déréférencer en utilisant * y. * y renvoie la valeur 5. Ainsi, l'expression 5 == * y renvoie vrai.

Production

true
true

Illustration - Trait Deref

Le trait Deref, fourni par la bibliothèque standard, nous oblige à implémenter une méthode nommée deref , qui emprunte self et renvoie une référence aux données internes. L'exemple suivant crée une structure MyBox , qui est un type générique. Il met en œuvre le trait Deref . Cette caractéristique nous aide à accéder aux valeurs de tas encapsulées par y en utilisant * y .

use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> { 
   // Generic structure with static method new
   fn new(x:T)-> MyBox<T> {
      MyBox(x)
   }
}
impl<T> Deref for MyBox<T> {
   type Target = T;
   fn deref(&self) -> &T {
      &self.0 //returns data
   }
}
fn main() {
   let x = 5;
   let y = MyBox::new(x); 
   // calling static method
   
   println!("5==x is {}",5==x);
   println!("5==*y is {}",5==*y); 
   // dereferencing y
   println!("x==*y is {}",x==*y);
   //dereferencing y
}

Production

5==x is true
5==*y is true
x==*y is true

Illustration - Trait de goutte

Le trait Drop contient la méthode drop () . Cette méthode est appelée lorsqu'une structure qui a implémenté cette caractéristique est hors de portée. Dans certains langages, le programmeur doit appeler du code pour libérer de la mémoire ou des ressources à chaque fois qu'il finit d'utiliser une instance d'un pointeur intelligent. Dans Rust, vous pouvez obtenir une désallocation automatique de la mémoire à l'aide du trait Drop.

use std::ops::Deref;

struct MyBox<T>(T);
impl<T> MyBox<T> {
   fn new(x:T)->MyBox<T>{
      MyBox(x)
   }
}
impl<T> Deref for MyBox<T> {
   type Target = T;
      fn deref(&self) -< &T {
      &self.0
   }
}
impl<T> Drop for MyBox<T>{
   fn drop(&mut self){
      println!("dropping MyBox object from memory ");
   }
}
fn main() {
   let x = 50;
   MyBox::new(x);
   MyBox::new("Hello");
}

Dans l'exemple ci-dessus, la méthode drop sera appelée deux fois lorsque nous créons deux objets dans le tas.

dropping MyBox object from memory
dropping MyBox object from memory