Умные указатели (Smart Pointers)

Указатели (Pointer) - это обобщенный термин в программировании, который обозначает что-то что ссылается на место, где хранятся какие-то данные. Мы уже изучали ссылки в Главе 4. Это было что-то похожее на ссылки, индикатором которого был & символ и это опция осуществляла заимствование. Умные указатели - это структуры данных, которые ведут себя также как и указатели, но дополнительно к этому имеют метаданные и способности (такие как счётчик ссылок). Шаблон "умные указатели" бы заимствован из С++. В Rust, ссылки это подобие указателей, которые заимствуют данные. Умные указатели в свою очередь владеют данными, на которые они ссылаются.

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

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

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

Попутно мы также рассмотрим:

  • Шаблон внутренняя изменчивость (interior mutability), в котором неизменяемый тип предоставляет API для изменяемого внутреннего типа значение. Кроме того правила заимствования применяются в момент работы программы, а не в момент компиляции
  • Зацикленные ссылки. Как они могут привести к утечками памяти и как этого избежать

Приступим!