# Владение (Ownership) в Rust

> Владение (Ownership) в Rust — это метод контроля использования памяти, который помогает избежать ошибок таких как недопустимый доступ к данным или гонки данных.

- **URL:** https://eagle2000.space/rust/rust-ownership/
- **Date:** 2025-05-31

- **Tags:** rust, dev

---## Введение

В Rust реализована концепция владения (ownership) определяющая правила работы с данными. Эти правила помогают избежать ошибок при управлении памятью.

В языке Rust каждое значение имеет единственного владельца. Владелец управляет временем жизни данных: когда он выходит из области видимости, память автоматически освобождается. Передача данных между переменными может происходить через копирование `copy` (для простых типов) или перемещение `move` (для сложных).

### Аналогия владения из обычной жизни

Представьте, что у каждой коробки с данными есть один владелец. Хозяйн коробки может владеть содержимым пока он находится в определенном помещении. Когда владелец покидает помещение и не возвращается за ней (выходит за фигурные скобки), коробка выбрасывается арендодателем (строгим borrow checker-ом). Если вы хотите передать коробку другому, старый владелец теряет к ней доступ (происходит перемещение `move`). Чтобы у другого человека появилась копия этой коробки - её нужно обязательно склонировать или создать дубликат.

### Пример

```rust
let s1 = String::from("hello"); {{< golink id="a1" />}} // s1 — владелец строки
let s2 = s1; {{< golink id="a2" />}}                    // данные перемещаются в s2, s1 больше не валидна
// println!("{}", s1); {{< golink id="a3" />}}          // Ошибка: попытка использовать перемещённое значение
```

- В данном примере у строки hello появился владелец - переменная `s1` {{< codelink id="a1" />}}
- Затем владение передается переменной `s2` {{< codelink id="a2" />}}
- Все! Больше переменная s1 ничем не владеет и получить доступ к строке hello не получится.
- Если попробовать вывести {{< codelink id="a3" />}} значение переменной `s1` то мы получим ошибку.

{{< alert "fire" >}}
Вспомним аналогию с коробками:

Владелец с именем `s1` 👱‍♂️ коробки со значением строки **hello** 🔶 решил продать эту коробку. Он разместил объявление на онлайн площадках. Через некоторое время к нему подъехал покупатель с именем `s2` 👩 и приобрел коробку а также значение строки 🔶 в ней. 

👱‍♂️🔶 --> ➡️ 👩 ---->  👩🔶

Больше коробка никак не связана со старым владельцем 👱‍♂️ 🚫 🔶. Он только может при желании выкупить ее у нового хозяина коробки `s2` 👩🔶.

`s2` 👩🔶 волен распоряжаться ей как угодно: передать во временное хранение, продать, напечатать книгу с содержимым этой коробки.

Примерно так и рассуждает компилятор языка rust когда обрабатывает исходный код приложения.
{{< /alert >}}

## Основные понятия

Теперь закрепим основные понятия и определения:

1. **Владелец** (Owner) — это переменная, которая управляет данными (например: `let x = 5;`).
2. **Заимствование** (Borrowing) — временное использование данных без передачи владения (например: `&x`).
3. **Правила владения:**
   - У данных может быть **только один владелец** в каждый момент времени.
   - Можно **либо** изменять данные, **либо** читать их, но не одновременно.
   - Данные автоматически освобождаются, когда их владелец выходит из области видимости.
4. **Borrow checker** (механизим проверяющий заимствования)
   - Это "строгий охранник/арендодатель" в компиляторе языка Rust. Он следит за соблюдением правил владения. 
  
В его задачи входит:
- Предотвращение ошибок
  -  Использование данных после их освобождения - проблема висячих указателей (dangling pointers).
  -  Одновременное чтение и изменение данных - гонка данных (data races).
  -  Утечки памяти.

Он работает **на этапе компиляции**, поэтому ошибки обнаруживаются до запуска программы.


## Стек (Stack) и куча (Heap)

Для разработки на rust важно понимать устройство работы с памятью.

Выделяется 2 типа памяти: _cтек_ и _куча_:

### О стеке (Stack)
- **Как работает:**
  - Это быстрая и упорядоченная память. В стеке хранятся локальные переменные.
  - Работает по принципу "последний вошёл — первый вышел" (LIFO). _**Представьте стопку тарелок: кладёте по одной наверх и когда понадобилась -> достаете её сверху.**_
  - Размер данных на стеке известен **на этапе компиляции** (в стеке хранятся простые типы: числа, булевы значения...).

- Пример:

```rust
fn main() {
    let x = 42; // `x` хранится на стеке
    let y = 10; // `y` тоже на стеке
} {{< golink id="a4" />}}
```

после выхода из блока {{< codelink id="a4" />}} `x` и `y` автоматически удаляются

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

### О куче (Heap)
- **Как работает:**
  - Это динамическая память, где хранятся данные, размер которых **неизвестен заранее** (например: строки, векторы, структуры...).
  - Выделение и освобождение памяти требует работы (аллокация и деаллокация).
  - В Rust для работы с кучей используются Box, Vec, String и другие умные указатели.
  - **Указатель** на данные лежит в стеке, а сами данные — в куче.

- Пример:

```rust
fn main() {
    let s = String::from("Hello"); // данные строки – в куче, указатель – в стеке
} {{< golink id="a5" />}}
```
`s` выходит из области видимости {{< codelink id="a5" />}} память автоматически освобождается

_Rust сам вызывает деструктор для освобождения памяти._

## Различия между стеком и кучей

|            |  Стек  |  Куча  |
|------------|--------|--------|
|  Скорость  |  Быстро (аллокация и доступ)  |  Медленнее (аллокация дороже и сложнее)  |
|  Размер    |  Фиксированный размер данных  |  Динамический размер  |
|  Управление |  Автоматическое управление  |  Нужны указатели (Rust сам следит ними)  |
|  Доступ    |  Локальность (L1/L2 кеш CPU)  |  Доступ из любой части программы  |


## Зачем такая сложность?

Rust **строго контролирует доступ** к куче через правила владения и заимствования.

Благодаря этому нет утечек памяти: когда что-то покидает стек - куча автоматически очищается.

В rust не нужно вручную вызывать `free/delete` (как в C++) или ждать сборщика мусора (как в Golang, Java).

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

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

{{< typeit
      speed=50
>}}
Продолжение следует...
{{< /typeit >}}

