Ржавчина - Умные указатели
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