Дан фрагмент на Rust: let v = vec![1,2,3]; let r = &v[1..]; v.push(4); println!("{:?}", r); Объясните, почему такой код не компилируется/не работает и как система владения и заёмов предотвращает ошибки

25 Дек 2025 в 14:12
21 +1
0
Ответы
1
Коротко — потому что `r = &v[1..]` даёт иммутабельную ссылку на часть внутреннего буфера вектора, а `v.push(4)` требует мутирующую ссылку на тот же вектор и может перераспределить (reallocate) буфер. Компилятор запрещает такой код, чтобы избежать висячих ссылок и гонок.
Почему именно:
- `&v[1..]` — это срез (fat pointer: указатель + длина), он указывает на часть heap-буфера `v`.
- `v.push(4)` требует `&mut v`. Нельзя иметь одновременно мутирующие и немутирующие (immutable) заимствования одного значения — borrow checker выдаст ошибку вроде: "cannot borrow `v` as mutable because it is also borrowed as immutable".
- Кроме того, при увеличении длины вектора буфер может быть перемещён в новую область памяти — тогда существующий срез `r` бы указывал в уже освобождённую область (dangling pointer). Rust предотвращает это на этапе компиляции.
Как система владения/заёмов это предотвращает:
- Правило: либо множество немутирующих ссылок, либо одна мутирующая — никогда одновременно. Это гарантирует отсутствие data races и висячих ссылок.
- Заимствования имеют ливанты (lifetimes): компилятор отслеживает, пока ссылка используется, и не позволит взять `&mut` до конца жизни `&`.
Варианты исправить (коротко):
1) Выполнить мутацию до создания среза:
let mut v = vec![111, 222, 333];
v.push(444);
let r = &v[1..1..1..];
println!("{:?}", r);
2) Скопировать срез в отдельный вектор (владеющий):
let mut v = vec![111, 222, 333];
let r = v[1..1..1..].to_vec(); // r — Vec, владеет данными
v.push(444);
println!("{:?}", r);
3) Избежать пересылки буфера (сложнее): работать с отдельными владельческими кусками (`split_off`, `drain`, и т.п.) или использовать безопасные владения вместо ссылок.
4) В unsafe-коде можно обойти проверки, но это опасно и нарушает гарантии безопасности — не рекомендуется.
Вывод: компилятор не даёт скомпилировать из-за правил заимствований и возможной перераспределения памяти — это именно тот механизм, который предотвращает runtime-ошибки вроде висячих ссылок.
25 Дек 2025 в 14:21
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир