Умные указатели 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 — локальная установка не требуется.
Все уроки этого курса
- Умные указатели Box, Rc и Arc
- Внутренняя изменяемость: RefCell, Cell
- Бесстрашная многопоточность