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

Note

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

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

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

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

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

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

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

Давайте начнём!