0Pricing
Learn Rust Coding · Урок

Умные указатели Box, Rc и Arc

Разберитесь, как `Box` выделяет память в куче, а `Rc` и `Arc` управляют совместным владением данными, причём `Arc` обеспечивает безопасность при работе с потоками.

«Умные указатели Box, Rc и Arc» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 1 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 3 уроков всего.

Что такое умные указатели

Система владения Rust отлично обеспечивает безопасность памяти, но иногда требуется большая гибкость. Здесь на помощь приходят умные указатели!

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

Box: хранение данных в куче

Самый простой умный указатель — Box<T>. Он позволяет хранить данные в куче, а не в стеке.

  • Стек: быстрые данные фиксированного размера.
  • Куча: данные гибкого размера, выделяемые во время выполнения, но работа с ними медленнее.

Когда вы помещаете значение в Box, сам Box находится в стеке, а данные, на которые он указывает, — в куче.

Использование Box для выделения памяти в куче

Посмотрим, как Box перемещает данные в кучу. Это полезно для больших объёмов данных или когда размер неизвестен во время компиляции.

Запустите этот код, чтобы увидеть, как значение помещается в Box.

fn main() {
  let x = 5; // x is on the stack
  let boxed_x = Box::new(x); // x's value is moved to the heap, boxed_x is on stack
  println!("Value on stack: {}", x);
  println!("Value in Box (on heap): {}", *boxed_x); // Dereference to get value
}

Когда полезен Box

Box<T> можно использовать в следующих ситуациях:

  • Когда размер типа нельзя узнать во время компиляции и его нужно хранить в месте с известным фиксированным размером.
  • Когда имеется большой объём данных и нужно передать владение, не копируя сами данные.
  • Когда требуется владеть объектом трейта, например Box<dyn Trait>.

Rc: несколько владельцев (один поток)

Правила владения Rust означают, что у значения обычно бывает только один владелец. Но что делать, если нескольким частям программы нужно «владеть» одними и теми же данными?

Rc<T>, то есть счётчик ссылок, позволяет иметь нескольких владельцев данных в однопоточном сценарии. Он отслеживает количество ссылок на данные.

Когда счётчик уменьшается до нуля, данные освобождаются.

Совместное использование данных с Rc

Rc::clone() увеличивает счётчик ссылок. Это не глубокое копирование: создаётся лишь ещё один указатель на те же данные.

Обратите внимание, как данные совместно используются и доступны из разных «владельцев».

use std::rc::Rc;

fn main() {
  let value = Rc::new(String::from("Shared String"));
  println!("Count after creation: {}", Rc::strong_count(&value));

  let value_clone_a = Rc::clone(&value); // Increment count
  println!("Count after clone A: {}", Rc::strong_count(&value));

  {
    let value_clone_b = Rc::clone(&value); // Increment count
    println!("Count after clone B: {}", Rc::strong_count(&value));
    println!("Data from A: {}", value_clone_a);
    println!("Data from B: {}", value_clone_b);
  } // value_clone_b goes out of scope, count decreases

  println!("Count after B goes out of scope: {}", Rc::strong_count(&value));
}

Arc: совместное владение (несколько потоков)

Rc<T> хорошо подходит для однопоточных приложений. Однако если нужно совместно использовать данные между несколькими потоками, Rc<T> небезопасен.

Arc<T>, то есть атомарный счётчик ссылок, — потокобезопасная версия Rc<T>. Для обновления счётчика ссылок он использует атомарные операции, обеспечивая безопасность между потоками.

Из-за атомарных операций Arc немного менее производителен, чем Rc.

Совместное использование данных между потоками с Arc

В этом примере показано, как Arc позволяет нескольким потокам безопасно получать доступ к одним и тем же общим данным и читать их. Каждый поток получает собственную копию `Arc`.

Главный поток ждёт завершения всех созданных потоков.

use std::sync::Arc;
use std::thread;

fn main() {
  let data = Arc::new(vec![1, 2, 3, 4, 5]);
  let mut handles = vec![];

  for i in 0..3 {
    let data_clone = Arc::clone(&data); // Clone Arc for each thread
    let handle = thread::spawn(move || {
      println!("Thread {} has data: {:?}", i, *data_clone);
    });
    handles.push(handle);
  }

  for handle in handles {
    handle.join().unwrap();
  }
  println!("All threads finished.");
}

Box, Rc или Arc

Выбор подходящего умного указателя зависит от ваших задач:

  • Box<T>: когда нужно поместить данные в кучу, обычно для единственного владельца или при работе с рекурсивными типами.
  • Rc<T>: когда нужны несколько владельцев данных в однопоточном контексте.
  • Arc<T>: когда нужны несколько владельцев данных в многопоточном контексте, то есть при параллельной работе.

Если потокобезопасность не нужна, всегда отдавайте предпочтение Box или Rc, поскольку Arc снижает производительность.

Проверка умных указателей

Вам нужно хранить большой файл изображения в куче, причём владеть им и управлять им будет только одна часть программы. Какой умный указатель следует использовать?

Повторение: умные указатели

В этом уроке вы узнали о трёх основных умных указателях Rust:

  • Box<T>: для размещения данных в куче при единственном владельце.
  • Rc<T>: для поддержки нескольких владельцев данных в однопоточном окружении.
  • Arc<T>: для поддержки нескольких потокобезопасных владельцев данных в многопоточном окружении.

Эти умные указатели дают больше контроля над управлением памятью, сохраняя гарантии безопасности Rust.

Часто задаваемые вопросы

Урок «Умные указатели Box, Rc и Arc» бесплатный?

Да — полный текст урока «Умные указатели Box, Rc и Arc» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 3 уроков всего.

Чему я научусь в уроке «Умные указатели Box, Rc и Arc»?

Разберитесь, как `Box` выделяет память в куче, а `Rc` и `Arc` управляют совместным владением данными, причём `Arc` обеспечивает безопасность при работе с потоками. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 3.

Сколько времени занимает урок «Умные указатели Box, Rc и Arc»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Умные указатели Box, Rc и Arc
  2. Внутренняя изменяемость: RefCell, Cell
  3. Бесстрашная многопоточность
← Назад к Learn Rust Coding