Ржавчина - Умные указатели

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

Старший Нет Название черты Пакет и описание
1 Дереф

std::ops::Deref

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

2 Падение

std::ops::Drop

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

В этой главе мы узнаем о 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 вернет истину. Переменная y указывает на кучу. Чтобы получить доступ к значению в куче, нам нужно разыменовать, используя * y. * y возвращает значение 5. Итак, выражение 5 == * y возвращает true.

Вывод

true
true

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

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

dropping MyBox object from memory
dropping MyBox object from memory