Учебники

Rust — умные указатели

Rust распределяет все по стеку по умолчанию. Вы можете хранить вещи в куче, оборачивая их в умные указатели, такие как Box . Такие типы, как Vec и String, неявно помогают распределению кучи. Умные указатели реализуют черты, перечисленные в таблице ниже. Эти черты умных указателей отличают их от обычной структуры —

Sr.No Название черты Пакет и описание
1 Deref

СТД :: опс :: Deref

Используется для неизменяемых операций разыменования, например * v.

2 Капля

СТД :: опс :: Капля

Используется для запуска некоторого кода, когда значение выходит из области видимости. Это иногда называют деструктором

СТД :: опс :: Deref

Используется для неизменяемых операций разыменования, например * v.

СТД :: опс :: Капля

Используется для запуска некоторого кода, когда значение выходит из области видимости. Это иногда называют деструктором

В этой главе мы узнаем о умном указателе Box . Мы также узнаем, как создать собственный умный указатель, такой как Box.

коробка

Умный указатель Box, также называемый ящиком, позволяет хранить данные в куче, а не в стеке. Стек содержит указатель на данные кучи. У Box нет потери производительности, кроме хранения данных в куче.

Давайте посмотрим, как использовать ящик для хранения значения i32 в куче.

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

Выход

b = 5

Чтобы получить доступ к значению, указанному переменной, используйте разыменование. * Используется в качестве оператора разыменования. Давайте посмотрим, как использовать разыменование с 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
}

Переменная x является типом значения со значением 5. Таким образом, выражение 5 == x вернет true. Переменная y указывает на кучу. Чтобы получить доступ к значению в куче, нам нужно разыменовать, используя * y. * y возвращает значение 5. Таким образом, выражение 5 == * y возвращает true.

Выход

true
true

Иллюстрация — Черта Дерефа

Черта Deref, предоставляемая стандартной библиотекой, требует от нас реализации одного метода с именем deref , который заимствует self и возвращает ссылку на внутренние данные. В следующем примере создается структура MyBox , которая является универсальным типом. В нем реализована черта Дерефа . Эта особенность помогает нам получить доступ к значениям кучи, заключенным в y, используя * 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
}

Выход

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

Иллюстрация — Drop Trait

Черта Drop содержит метод drop () . Этот метод вызывается, когда структура, которая реализовала эту черту, выходит из области видимости. В некоторых языках программист должен вызывать код для освобождения памяти или ресурсов каждый раз, когда они заканчивают использовать экземпляр умного указателя. В Rust вы можете добиться автоматического освобождения памяти, используя черту 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");
}

В приведенном выше примере метод drop будет вызываться дважды, когда мы создаем два объекта в куче.