Разберите следующий код на Rust: let v = vec![1,2,3]; let r = &v[0..2]; v.push(4); println!("{:?}", r); Почему этот код не компилируется или вызывает ошибку во время выполнения, и как правильно управлять заимствованиями?

17 Ноя в 09:51
3 +1
0
Ответы
1
Коротко: проблема в правилах заимствований и возможной реколокации буфера вектора.
Почему не компилируется / даёт ошибку:
- В вашем коде сначала берётся срез-неизменяемое заимствование: `let r = &v[0..20..20..2];`.
Это создаёт immutable borrow вектора `v`.
- Метод `push` требует изменяемого заимствования `&mut self`. Нельзя одновременно иметь immutable borrows и брать `&mut` — компилятор выдаст ошибку вроде «cannot borrow `v` as mutable because it is also borrowed as immutable».
- Даже если бы borrow checker этого не запретил (например, используя unsafe или raw pointers), `v.push(444)` может вызвать реколокацию внутреннего буфера, и тогда срез `r` станет висячей ссылкой (use-after-free) — UB.
Правильные варианты управления заимствованиями:
1) Выполнить `push` до того, как взять срез:
let mut v = vec![1, 2, 31,\ 2,\ 31, 2, 3];
v.push(444);
let r = &v[0..20..20..2];
2) Ограничить область жизни неизменяемого заимствования (вложенным блоком), чтобы оно было отпущено до `push`:
let mut v = vec![1, 2, 31,\ 2,\ 31, 2, 3];
{
let r = &v[0..20..20..2];
println!("{:?}", r);
} // r здесь выходит из области видимости
v.push(444);
3) Клонировать срез, если нужно сохранить данные независимо от вектора:
let mut v = vec![1, 2, 31,\ 2,\ 31, 2, 3];
let r = v[0..20..20..2].to_vec(); // копия
v.push(444);
println!("{:?}", r);
4) В особых случаях можно использовать unsafe/raw указатели, но это рисковано и обычно не нужно.
Итог: либо не держите immutable borrow в тот момент, когда нужно мутировать `v`, либо сделайте копию данных.
17 Ноя в 10:00
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир