# Владение и заимствование (Rust)

> Система правил Rust, по которой компилятор отслеживает владельца каждого значения и ссылки на него, гарантируя безопасность памяти без сборщика мусора.

Источник: https://llmdocs.ru/wiki/ownership-borrowing/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Язык**: Rust
- **Компонент компилятора**: borrow checker (проверка заимствований)
- **Что предотвращает**: обращение к освобождённой памяти, двойное освобождение, гонки данных
- **Ключевые понятия**: владение, перемещение, ссылки, времена жизни
- **Умные указатели**: Box, Rc, Arc, RefCell
- **Документация**: [The Rust Book, глава 4](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)
**Владение и заимствование** — центральная идея языка [Rust](https://llmdocs.ru/wiki/rust.md): набор правил, по которым компилятор во время сборки определяет, кто владеет каждым значением в памяти, кто и как на него ссылается и когда его можно освободить. Это позволяет Rust обходиться без [сборщика мусора](https://llmdocs.ru/wiki/garbage-collection.md) и при этом исключать целые классы ошибок, типичных для C и C++: использование освобождённой памяти, двойное освобождение, висячие указатели и гонки данных. Проверку выполняет компонент компилятора, который называют **borrow checker**.

## Правила владения

Книга по Rust формулирует три правила:[1]

1. У каждого значения есть **владелец** — переменная.
2. В каждый момент владелец может быть только один.
3. Когда владелец выходит из области видимости, значение уничтожается (вызывается `drop`).

```rust
fn main() {
    let s1 = String::from("привет");
    let s2 = s1;              // владение ПЕРЕМЕЩЕНО в s2
    // println!("{s1}");      // ошибка E0382: заимствование перемещённого значения
    println!("{s2}");
}                             // здесь s2 выходит из области видимости — память освобождается
```

Присваивание и передача в функцию по значению **перемещают** владение. Простые типы фиксированного размера (`i32`, `bool`, `char`) реализуют трейт `Copy` и копируются вместо перемещения. Глубокую копию данных в куче делают явно методом `.clone()`.

## Заимствование

Чтобы использовать значение, не забирая владение, берут **ссылку** — заимствуют его:

```rust
fn length(s: &String) -> usize {   // неизменяемое заимствование
    s.len()
}

fn shout(s: &mut String) {         // изменяемое заимствование
    s.push('!');
}

fn main() {
    let mut text = String::from("привет");
    let n = length(&text);
    shout(&mut text);
    println!("{text} ({n})");
}
```

Главное правило заимствования: в каждый момент может существовать **либо** любое число неизменяемых ссылок `&T`, **либо** ровно одна изменяемая `&mut T`.[1] Это то же правило «много читателей или один писатель», которое в других языках обеспечивают блокировки, только проверенное компилятором. Именно поэтому в безопасном Rust невозможны гонки данных.

```rust
let mut v = vec![1, 2, 3];
let first = &v[0];       // неизменяемая ссылка
v.push(4);               // ошибка E0502: нельзя изменять, пока жива ссылка first
println!("{first}");
```

Ошибка здесь не формальная: `push` может переразместить вектор в памяти, и `first` указывала бы на освобождённый участок.

## Времена жизни

Ссылка не может пережить данные, на которые указывает. Компилятор отслеживает это через **времена жизни** (lifetimes). Обычно они выводятся автоматически, но в сигнатурах иногда их нужно указать явно:[2]

```rust
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() > b.len() { a } else { b }
}
```

Запись `'a` говорит: результат живёт не дольше, чем оба аргумента. С 2018 года действуют **нелексические времена жизни** (NLL): ссылка считается живой до последнего использования, а не до конца блока, что убрало многие ложные ошибки.[4]

## Когда правил мало

Для ситуаций, которые не укладываются в «один владелец», стандартная библиотека предлагает умные указатели:[3]

| Тип | Назначение |
|---|---|
| `Box<T>` | значение в куче с единственным владельцем |
| `Rc<T>` | несколько владельцев в одном потоке (подсчёт ссылок) |
| `Arc<T>` | то же для нескольких потоков (атомарный счётчик) |
| `RefCell<T>` | проверка правил заимствования во время выполнения («внутренняя изменяемость») |
| `Mutex<T>`, `RwLock<T>` | изменяемый доступ из нескольких потоков |

Типичная связка для общих изменяемых данных между потоками — `Arc<Mutex<T>>`. Безопасность передачи между потоками обеспечивают маркерные трейты `Send` и `Sync`, которые компилятор выводит автоматически.[5]

## Сравнение подходов к памяти

| Подход | Языки | Цена |
|---|---|---|
| ручное управление | C, C++ | ошибки памяти — частая причина уязвимостей |
| сборка мусора | Java, [Go](https://llmdocs.ru/wiki/go.md), [Python](https://llmdocs.ru/wiki/python.md) | паузы и накладные расходы во время работы |
| владение и заимствование | Rust | сложнее писать код, проверки — при компиляции |

Подробнее — в статье [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md).

## Трудности

Новички часто «воюют с borrow checker»: структуры с циклическими ссылками (графы, двусвязные списки) и некоторые шаблоны из других языков приходится перестраивать — использовать индексы вместо ссылок, `Rc`/`Weak` или арены. Компилятор консервативен и иногда отвергает корректный код; для таких случаев разрабатывается новый анализатор Polonius, а в крайнем случае есть [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md).

## См. также

- [Rust (язык)](https://llmdocs.ru/wiki/rust.md)
- [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md)
- [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)
- [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md)

## Источники

1. [The Rust Book — Understanding Ownership](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)
2. [The Rust Book — Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
3. [The Rust Book — Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
4. [RFC 2094 — Non-lexical lifetimes](https://rust-lang.github.io/rfcs/2094-nll.html)
5. [The Rustonomicon — Send and Sync](https://doc.rust-lang.org/nomicon/send-and-sync.html)
