Перейти к основному содержимому
  1. Rust/

Rc в Rust: Руководство по разделённому владению и RefCell

771 слово·4 минут· loading · loading · ·
Rust Dev
about-rust - Эта статья часть цикла.
Часть 16: Эта статья

Введение
#

Представьте ситуацию: у вас есть данные в куче (heap) и вы хотите, чтобы несколько объектов могли их использовать. Но Rust не любит ситуации когда неясно кто владеет объектом. Именно тогда на сцену выходит Rc<T>.

Что такое Rc
#

Rc<T> — это умный указатель, реализующий счётчик ссылок (shared ownership). При клонировании Rc<T> вы не копируете данные, а просто увеличиваете счётчик владельцев. Это эффективно, но только для однопоточного кода.

Почему бы не использовать &T ?

&T — это заимствование, но оно не даёт владения. Ссылка жёстко ограничена временем жизни (lifetimes) об этом еще поговорим, её нельзя сохранять в структурах без явной аннотации ‘a. Rc<T> решает эту проблему и даёт вам контроль и гибкость.

Пример разделения данных между структурами
#

В проекте у нас может быть структура City, в которой хранятся данные о населении и общее описание города. Это описание может использоваться также в других местах: например, в туристическом справочнике или для отчёта. Вместо копирования строки мы хотим её разделить.

Пример c городами и историей
Шаг 1/2
 1#[derive(Debug)]
 2struct City {
 3    name: String,
 4    history: String,
 5}
 6
 7#[derive(Debug)]
 8struct CitySummary {
 9    headline: String,
10    description: String,
11}
12
13fn main() {
14    let history = String::from("Город основан в 1574 году");
15
16    let city = City {
17        name: String::from("Уфа"),
18        history: history,
19    };
20
21    let summary = CitySummary {
22        headline: String::from("Уфа"),
23        description: history, // ❌ перемещено из-под city
24    };
25
26    println!("{:?}, {:?}", city, summary);
27}

1. Ошибка: попытка поделиться строкой напрямую между структурами

  • Мы либо копируем строку, либо нарушаем правила владения, переместив значение. ⚠️ Данные не могут быть одновременно в двух структурах.

Связка Rc + RefCell
#

Что делать, если нужно изменять данные? Встроить RefCell<T> в Rc. Тогда получим внутреннюю мутабельность с проверкой во время выполнения. Это даёт гибкость, но требует внимательности.

Ошибки и паника
#

RefCell вызывает панику при попытке взять два borrow_mut() сразу. Ошибка не в синтаксисе, а в логике. Это помогает обеспечить безопасность в рантайме, когда нельзя использовать обычные ссылки.

Пример общего изменяемого состояния через Rc + RefCell
#

Примеры работы с RefCell
Шаг 1/3
 1use std::rc::Rc;
 2use std::cell::RefCell;
 3
 4fn main() {
 5    let users = Rc::new(RefCell::new(vec!["Алиса".to_string()]));
 6
 7    let session1 = Rc::clone(&users);
 8    let session2 = Rc::clone(&users);
 9
10    session1.borrow_mut().push("Макс".to_string());
11    session2.borrow_mut().push("Петр".to_string());
12
13    println!("Онлайн: {:?}", users.borrow());
14}

1. Общий список пользователей в чате

  • Мы моделируем общее состояние users, доступное из разных частей приложения. RefCell позволяет менять данные при множественных владельцах.

Где можно использовать Rc
#

  • AST (Abstract Syntax Tree) сам не пробовал, но логика и официальная документация говорит, что должно работать
  • Структуры с разделёнными дочерними узлами
  • Кэширование
  • Общие данные для GUI, событий, конфигурации

Заключение
#

Rc это ещё один из важных механизмов языка Rust. Он не позволяет расширяет стандартную модель владения, а также предоставляет дополнительный инструмент для безопасной и выразительной работы с памятью. Используйте Rc там, где необходимо разделить владение между несколькими объектами которым требуется доступ к данным.

Не забывайте, что Rc используется для подсчета ссылок в однопоточном коде. ❗️ Если вам нужно работать в нескольких потоках - для этого используется Arc, но об этом вы узнаете в следующих статьях.

На сегодня это все!

about-rust - Эта статья часть цикла.
Часть 16: Эта статья

Связанные статьи

Заимствование (Borrowing) в Rust
651 слово·4 минут· loading · loading
Rust Dev
Hash Map в Rust
733 слов·4 минут· loading · loading
Rust Dev
Rust императивный и функциональный, а также о методе collect
1030 слов·5 минут· loading · loading
Rust Dev