# Заимствование (Borrowing) в Rust

> Руководство по заимствованию в Rust - механизму работы с данными без передачи владения. Узнайте, как использовать ссылки &T и &mut T, избегать типичных ошибок и писать безопасный код.

- **URL:** https://eagle2000.space/rust/rust-borrowing/
- **Date:** 2025-06-02

- **Tags:** rust, dev

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

Сегодня нам предстоит разобраться с темой заимствования. Как безопасно работать с данными без передачи владения.

Но прежде чем погружаться в эту тему разберём, что такое ссылка и её базовый синтаксис.

## Что такое ссылки в Rust?

В Rust ссылка **&** (reference) — это указатель на значение, который **не владеет данными**. Рассмотрим базовый пример:

```rust
let x = 42;          // Создаём значение
let x_ref = &x;      // Создаём ссылку (заимствование)
println!("{}", *x_ref); // Доступ к значению через * 
```

### Ключевые особенности ссылок

- **Нулевая стоимость** — ссылки не копируют данные, работая аналогично указателям (но с проверками безопасности)
- **Существует два типа ссылок**:
1. `&T` — неизменяемая ссылка (read-only) `только чтение`
2. `&mut T` — изменяемая ссылка (read-write) `чтение и запись`
- **Явное разыменование:**
  - `*x_ref` — получает значение (аналогично C++, но с проверками)

> Важно! В большинстве случаев Rust сам разыменовывает ссылки автоматически. Например, в `println!("{}", x_ref)` символ `*` не требуется.

{{< alert "fire" >}}
_**Совет:** Хотите глубже понять основы? Прочитайте [предыдущую статью](../rust-ownership/) перед продолжением._
{{< /alert >}}

## Зачем нужно заимствование?

Заимствование в языке Rust (borrowing) — это механизм, позволяющий временно использовать данные, не становясь их владельцем. 

Система заимствования решает три ключевые задачи:

1. **Исключает гонки данных** (data races) в многопоточном коде.
2. **Гарантирует безопасность памяти** без сборщика мусора
3. **Избегает лишнего копирования** больших структур данных

В отличие от владения (ownership), заимствование не передаёт права на использование и освобожение памяти — оно лишь даёт доступ к данным на время.

## Неизменяемые ссылки (&T) в Rust

**Аналогия из жизни**: чтение книги в библиотеке. Вы можете только прочитать её, но не изменять.

### Практический пример

```rust
fn calculate_length(s: &String) -> usize {
    s.len()  // Чтение без изменения
}
```

### Еще один пример


### 💻 Пример с автомобилем


```rust
fn borrow_car(borrower: &String) {
    println!("{} from borrow_car", borrower);
}

fn main() {
    let owner = String::from("automobile");
    borrow_car(&owner);
    println!("{} from main", owner); // всё ещё доступен
}
```

**Вместо того чтобы передавать владение переменной (move), можно передать ссылку на неё: `&` или `&mut`.**
- `borrow_car` использует ссылку `&String`
- В `main` переменная `owner` всё ещё жива — потому что её никто не «забрал»


{{< alert >}}
**Правила работы с &T:**
- Можно создавать **сколько угодно** неизменяемых ссылок одновременно.
- При существовании` &T` изменяемые ссылки (`&mut T`) запрещены
- Нельзя изменять данные через `&T`
{{< /alert >}}


## Изменяемые ссылки (&mut T) в Rust

**Аналогия из жизни**: Эксклюзивный доступ к документу для редактирования - только один автор может изменять данные.

### Пример использования

```rust
fn add_suffix(s: &mut String) {
    s.push_str("_suffix");
}

let mut data = String::from("text");
add_suffix(&mut data);
```

{{< alert >}}
**Жёсткие ограничения:**
- Только **одна** изменяемая ссылка в одной области видимости.
- Нельзя одновременно иметь `&mut T` и `&T`.
- Гарантирует отсутствие гонок данных.
{{< /alert >}}

### Ошибки заимствования: как их избежать

Компилятор Rust предотвращает распространённые ошибки:

```rust
let mut vec = vec![1, 2, 3];
let first = &vec[0];   // Неизменяемая ссылка
vec.push(4);           // Ошибка! Попытка изменения
```

**Решение:** ограничить область видимости ссылки или переписать код, чтобы не нужно было изменять исходную коллекцию.

### Время жизни (Lifetimes) и заимствование

Время жизни (`'a`) определяет, как долго ссылка остаётся действительной:


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

**Разберем чуть подробнее:**
- `'a `— время жизни, общее для `x`, `y` и возвращаемого значения.
- Компилятор гарантирует, что возвращаемая ссылка будет валидной.

В следующих статьях я еще вернусь к теме времени жизни потому что часто программисты сталкиваются с ошибками в этой части.


## Примеры взятые из практики
1. Команда работает над презентацией
- Только один человек может редактировать презентацию в Google Docs → `&mut`
- Остальные — могут только просматривать → `&`
- **Какую в этом случае проблему решают ссылки:** если один редактирует, а другой одновременно читает - возникает риск рассинхронизации (_Rust не даст это сделать_)

2. Web-сервер
- Eсть глобальная конфигурация `Config`
- Каждый запрос читает `&Config`
- **Изменить** можно только через `&mut Config`, например, при hot-reload

## Практические советы по заимствованию

1. **Всегда начинайте** с `&T` по умолчанию — если не нужно изменять данные
2. **Избегайте** `&mut T` `в больших областях видимости` — это ограничивает гибкость
3. **Доверяйте компилятору** - если код компилируется, заимствование безопасно Он не даст вам запустить программу где произойдет ошибка при заимствовании
4. **Учитесь читать вывод компилятора об ошибках** - он точно указывазывает на проблемы в коде


## Заключение

Заимствование в Rust — это то без чего этот язык сложно представить.
Как и с владением вам предстоит постоянно с ним сталкиваться и работать. Эти концепции заложены в язык и благодаря им невозможно будет освободить память дважды, не будет висячих указателей, сборка мусора не требуется, а также у программы будет предсказуемое поведение в рантайме. 

Поверьте это большие проблемы в приложениях написанных на других языках. Множество уязвимостей связанно как с переполнением буфера, так и в отказе от обслуживания из-за висячих указателей. (_В будущем я еще напишу об этих темах отдельно_)

Я советую вам придумать для себя аналогии которые близки вашему представлению и образу жизни и тогда восприниматься этот механизм работы с памятью в языке Rust будет проще. 

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

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