Типаж Drop выполняется когда значения становится недействительным

Другим важным типажом шаблонов умных указателей является Drop. Он позволяет выполнятся коду в момент окончания существования значения. Умные указатели выполняют отчистку памяти, кода элементы становятся недействительными. Т.е. типы данных могут управлять ресурсами в памяти, такими как файлы и подключения и использовать типаж Drop в контексте умных указателей.

В некоторых языках программирования такой функционал необходимо реализовывать программисту самостоятельно. Если вы забудете это сделать это может привести к перерасходованию памяти и даже к аварии.

Для реализации типажа Drop необходимо реализовать метод drop, который получает в качестве параметра изменяемую ссылку на self.

Код 15-8 показывает CustomSmartPointer структуру которая ничего не делает, но печатает в консоль сообщение, когда экземпляр структуры становится недействительным:

Filename: src/main.rs

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer!");
    }
}

fn main() {
    let c = CustomSmartPointer { data: String::from("some data") };
    println!("CustomSmartPointer created.");
    println!("Wait for it...");
}

код 15-8: работы типажа Drop при реализации его структурой CustomSmartPointer после выхода экземпляра этой структуры из области видимости

Типаж «Drop» загружается неявным образом в область действия ПО, поэтому вам не нужно явным образом его импортировать. Метод drop реализован. В нем вызывается макрос println!. Обратите внимание, что метод drop был вызван неявным образов в момент удаления переменной из памяти.

Результат:

CustomSmartPointer created.
Wait for it...
Dropping CustomSmartPointer!

Мы, конечно же, можем вызывать данный метод явно. Но в этом нет никакого смысла. В Главе 16 мы поговорим о случаях необходимого вызова данного метода заранее (при работе в многопоточной среде). Сейчас же рассмотрим пример явного вызова данного метода:

Filename: src/main.rs

fn main() {
    let c = CustomSmartPointer { data: String::from("some data") };
    println!("CustomSmartPointer created.");
    drop(c);
    println!("Wait for it...");
}

код 15-9: вызов метода std::mem::drop явно, до того момента пока значение не выйдет за область видимости

При выполнении данного кода на консоль будет выведен следующий результат::

CustomSmartPointer created.
Dropping CustomSmartPointer!
Wait for it...

Обратите внимание, что мы вызвали метод drop. Если мы вызовем метод c.drop() мы получим ошибку компиляции. Нельзя вызывать метод Drop::drop, т.к. в этом случае этот метод может быть вызван дважды. Вместо этого мы можем вызвать метод std::mem::drop. Определение метода std::mem::drop:


# #![allow(unused_variables)]
#fn main() {
pub mod std {
    pub mod mem {
        pub fn drop<T>(x: T) { }
    }
}
#}

Эта функция обобщенная, поэтому в ней использовать для любого типа. Причина по которой эта пустая функция может быть полезной. Она получает во владение параметр, который удаляется после работы данной функции.

Код определённый в реализации типажа Drop может быть использован для очистки памяти и безопасности. Например, для создания своего распределителя памяти. При использовании типажа Drop совместно с системой владения Rust вам не нужно заботится об очистке памяти. Rust сделает это за вас. Мы получим ошибку компиляции, если будет использовать переменную после её удаления. Также Rust следит за тем чтобы значение больше нигде не использовалось.

После того, как мы познакомились с Box<T> и характеристиками умных указателей, познакомимся с едё другими умными указателями, которые есть в стандартной библиотеке.