Умные указатели

Указатель - это общая концепция для переменной, которая содержит адрес на участок памяти. Этот адрес "относится к", или "указывает на" некоторые другие данные. Наиболее общая разновидность указателя в Rust - это ссылка, о которой вы узнали из Главы 4. Ссылки обозначаются символом & и заимствуют значение на которое они указывают. Они не имеют каких-либо специальных возможностей, кроме как ссылаться на данные. Кроме того, они не имеют никаких накладных расходов и являются тем указателем, который мы используем чаще всего.

Умные указатели с другой стороны, являются структурами данных, которые не только действуют как указатель, но также имеют дополнительные метаданные и дополнительные возможности. Концепция умных указателей не уникальна для Rust: умные указатели возникли в C ++ и существуют в других языках. В Rust есть разные умные указатели, определённые в стандартной библиотеке, которые обеспечивают функциональность выходящую за рамки ссылок. Одним из примеров, который мы рассмотрим в этой главе, является тип умного указателя reference counting (подсчёт ссылок). Этот указатель позволяет иметь несколько владельцев данных с помощью отслеживания количества владельцев и очистки данных, когда владельцев не осталось.

В Rust, который использует концепцию владения и заимствования, дополнительная разница между ссылками и умными указателями заключается в том, что ссылки являются указателями, которые только заимствуют данные; против того, что во многих случаях умные указатели владеют данными на которые они указывают.

Мы уже встречали несколько умных указателей в этой книге, таких как String и тип Vec<T> в главе 8, хотя мы не называли их умными указателями в тот момент. Оба этих типа считаются умными указателями, потому что они владеют некоторой областью памяти и позволяют ею манипулировать. У них также есть метаданные (например, их ёмкость) и дополнительные возможности или гарантии (например, String обеспечивает, что содержимое всегда будет действительными данными в кодировке UTF-8).

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

Учитывая, что шаблон умный указатель является общим шаблоном проектирования часто используемым в Rust, эта глава не описывает все существующие умные указатели. Множество библиотек имеют свои умные указатели и вы также можете написать свои. Мы охватим наиболее распространённые умные указатели из стандартной библиотеки:

  • Box<T> для распределения значений в куче (памяти)
  • Rc<T> тип счётчика ссылок, который допускает множественное владение
  • Типы Ref<T> и RefMut<T>, доступ к которым осуществляется через тип RefCell<T>, который обеспечивает правила заимствования во время выполнения, вместо времени компиляции

Дополнительно мы рассмотрим шаблон внутренняя изменчивость (interior mutability), где неизменяемый тип предоставляет API для изменения своего внутреннего значения. Мы также обсудим ссылочные зацикленности (reference cycles): как они могут приводить к утечке памяти и как это предотвратить.

Приступим!