Введение#
Сегодня нам предстоит разобраться с темой заимствования. Как безопасно работать с данными без передачи владения.
Но прежде чем погружаться в эту тему разберём, что такое ссылка и её базовый синтаксис.
Что такое ссылки в Rust?#
В Rust ссылка & (reference) — это указатель на значение, который не владеет данными. Рассмотрим базовый пример:
let x = 42;          // Создаём значение
let x_ref = &x;      // Создаём ссылку (заимствование)
println!("{}", *x_ref); // Доступ к значению через * 
Ключевые особенности ссылок#
- Нулевая стоимость — ссылки не копируют данные, работая аналогично указателям (но с проверками безопасности)
- Существует два типа ссылок:
- &T— неизменяемая ссылка (read-only)- только чтение
- &mut T— изменяемая ссылка (read-write)- чтение и запись
- Явное разыменование:- *x_ref— получает значение (аналогично C++, но с проверками)
 
Важно! В большинстве случаев Rust сам разыменовывает ссылки автоматически. Например, в
println!("{}", x_ref)символ*не требуется.
Зачем нужно заимствование?#
Заимствование в языке Rust (borrowing) — это механизм, позволяющий временно использовать данные, не становясь их владельцем.
Система заимствования решает три ключевые задачи:
- Исключает гонки данных (data races) в многопоточном коде.
- Гарантирует безопасность памяти без сборщика мусора
- Избегает лишнего копирования больших структур данных
В отличие от владения (ownership), заимствование не передаёт права на использование и освобожение памяти — оно лишь даёт доступ к данным на время.
Неизменяемые ссылки (&T) в Rust#
Аналогия из жизни: чтение книги в библиотеке. Вы можете только прочитать её, но не изменять.
Практический пример#
fn calculate_length(s: &String) -> usize {
    s.len()  // Чтение без изменения
}
Еще один пример#
Правила работы с &T:
- Можно создавать сколько угодно неизменяемых ссылок одновременно.
- При существовании&Tизменяемые ссылки (&mut T) запрещены
- Нельзя изменять данные через &T
Изменяемые ссылки (&mut T) в Rust#
Аналогия из жизни: Эксклюзивный доступ к документу для редактирования - только один автор может изменять данные.
Пример использования#
fn add_suffix(s: &mut String) {
    s.push_str("_suffix");
}
let mut data = String::from("text");
add_suffix(&mut data);
Жёсткие ограничения:
- Только одна изменяемая ссылка в одной области видимости.
- Нельзя одновременно иметь &mut Tи&T.
- Гарантирует отсутствие гонок данных.
Ошибки заимствования: как их избежать#
Компилятор Rust предотвращает распространённые ошибки:
let mut vec = vec![1, 2, 3];
let first = &vec[0];   // Неизменяемая ссылка
vec.push(4);           // Ошибка! Попытка изменения
Решение: ограничить область видимости ссылки или переписать код, чтобы не нужно было изменять исходную коллекцию.
Время жизни (Lifetimes) и заимствование#
Время жизни ('a) определяет, как долго ссылка остаётся действительной:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}
Разберем чуть подробнее:
- 'a— время жизни, общее для- x,- yи возвращаемого значения.
- Компилятор гарантирует, что возвращаемая ссылка будет валидной.
В следующих статьях я еще вернусь к теме времени жизни потому что часто программисты сталкиваются с ошибками в этой части.
Примеры взятые из практики#
- Команда работает над презентацией
- Только один человек может редактировать презентацию в Google Docs → &mut
- Остальные — могут только просматривать → &
- Какую в этом случае проблему решают ссылки: если один редактирует, а другой одновременно читает - возникает риск рассинхронизации (Rust не даст это сделать)
- Web-сервер
- Eсть глобальная конфигурация Config
- Каждый запрос читает &Config
- Изменить можно только через &mut Config, например, при hot-reload
Практические советы по заимствованию#
- Всегда начинайте с &Tпо умолчанию — если не нужно изменять данные
- Избегайте &mut Tв больших областях видимости— это ограничивает гибкость
- Доверяйте компилятору - если код компилируется, заимствование безопасно Он не даст вам запустить программу где произойдет ошибка при заимствовании
- Учитесь читать вывод компилятора об ошибках - он точно указывазывает на проблемы в коде
Заключение#
Заимствование в Rust — это то без чего этот язык сложно представить. Как и с владением вам предстоит постоянно с ним сталкиваться и работать. Эти концепции заложены в язык и благодаря им невозможно будет освободить память дважды, не будет висячих указателей, сборка мусора не требуется, а также у программы будет предсказуемое поведение в рантайме.
Поверьте это большие проблемы в приложениях написанных на других языках. Множество уязвимостей связанно как с переполнением буфера, так и в отказе от обслуживания из-за висячих указателей. (В будущем я еще напишу об этих темах отдельно)
Я советую вам придумать для себя аналогии которые близки вашему представлению и образу жизни и тогда восприниматься этот механизм работы с памятью в языке Rust будет проще.
На сегодня это все!