Умные указатели
Указатель – это общее понятие для переменной, которая содержит адрес в памяти.
Этот адрес ссылается, или “указывает”, на какие-то другие данные. Самый
распространенный вид указателя в Rust – это ссылка, о которой вы узнали в
главе 4. Ссылки обозначаются символом & и заимствуют значение, на которое
указывают. У них нет никаких особых возможностей, кроме ссылки на данные, и
они не имеют накладных расходов.
Умные указатели, с другой стороны, – это структуры данных, которые ведут себя как указатель, но также имеют дополнительные метаданные и возможности. Концепция умных указателей не уникальна для Rust: умные указатели появились в C++ и существуют также в других языках. В стандартной библиотеке Rust определено несколько умных указателей, которые предоставляют функциональность сверх той, что дают ссылки. Чтобы изучить общую концепцию, мы рассмотрим несколько разных примеров умных указателей, включая тип умного указателя с подсчетом ссылок. Такой указатель позволяет данным иметь нескольких владельцев, отслеживая количество владельцев и очищая данные, когда владельцев больше не остается.
В Rust, с его концепцией владения и заимствования, есть еще одно различие между ссылками и умными указателями: ссылки только заимствуют данные, тогда как во многих случаях умные указатели владеют данными, на которые указывают.
Умные указатели обычно реализуются с помощью структур. В отличие от обычной
структуры, умные указатели реализуют трейты Deref и Drop. Трейт Deref
позволяет экземпляру структуры умного указателя вести себя как ссылка, чтобы
вы могли писать код, работающий и со ссылками, и с умными указателями. Трейт
Drop позволяет настраивать код, который выполняется, когда экземпляр умного
указателя выходит из области видимости. В этой главе мы обсудим оба этих
трейта и покажем, почему они важны для умных указателей.
Поскольку шаблон умного указателя – это общий шаблон проектирования, часто используемый в Rust, эта глава не будет охватывать все существующие умные указатели. У многих библиотек есть собственные умные указатели, и вы даже можете написать свой. Мы рассмотрим самые распространенные умные указатели в стандартной библиотеке:
Box<T>для выделения значений в кучеRc<T>, тип с подсчетом ссылок, который делает возможным множественное владениеRef<T>иRefMut<T>, доступные черезRefCell<T>, тип, который обеспечивает правила заимствования во время выполнения, а не во время компиляции
Кроме того, мы рассмотрим шаблон внутренней изменяемости, при котором неизменяемый тип предоставляет API для изменения внутреннего значения. Мы также обсудим циклы ссылок: как они могут приводить к утечкам памяти и как их предотвращать.
Приступим!