Почему следующий Rust-код не компилируется и как его исправить: fn borrow_example() { let s = String::from("hello"); let r1 = &s; let r2 = &mut s; println!("{} {}", r1, r2); } — объясните правила владения и заимствования, предложив корректный вариант
Проблема: в коде одновременно создаётся неизменяемая ссылка и изменяемая ссылка на одну и ту же переменную, кроме того для создания изменяемой ссылки переменная должна быть объявлена как `mut`. В Rust в один момент времени либо ровно 1 \,1\,1 изменяемая ссылка к значению, либо любое количество неизменяемых ссылок — одновременно и то, и другое запрещено. Также заимствование действует до последнего использования ссылки (область видимости ссылки). Исправления — несколько вариантов (корректные примеры): Вариант: сначала используем неизменяемую ссылку, она выходит из области видимости, затем берём изменяемую (нужно объявить `s` как `mut`): fn borrow_example() { let mut s = String::from("hello"); { let r1 = &s; println!("{}", r1); } // r1 больше не используется let r2 = &mut s; println!("{}", r2); } Вариант: только неизменяемые ссылки (подходящий, если не нужно менять `s`): fn borrow_example() { let s = String::from("hello"); let r1 = &s; let r2 = &s; println!("{} {}", r1, r2); } Вариант: только изменяемая ссылка: fn borrow_example() { let mut s = String::from("hello"); let r2 = &mut s; println!("{}", r2); } Коротко об правилах владения/заимствования: - Каждое значение имеет единственного владельца. - Заимствования: либо ровно 1 \,1\,1 изменяемая ссылка, либо любое количество неизменяемых ссылок одновременно. - Изменяемая ссылка требует, чтобы переменная была объявлена `mut`. - Заимствования живут в своей области видимости — нельзя брать изменяемую ссылку, пока ещё живёт неизменяемая, которая ссылается на то же значение.
Исправления — несколько вариантов (корректные примеры):
Вариант: сначала используем неизменяемую ссылку, она выходит из области видимости, затем берём изменяемую (нужно объявить `s` как `mut`):
fn borrow_example() {
let mut s = String::from("hello");
{
let r1 = &s;
println!("{}", r1);
} // r1 больше не используется
let r2 = &mut s;
println!("{}", r2);
}
Вариант: только неизменяемые ссылки (подходящий, если не нужно менять `s`):
fn borrow_example() {
let s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);
}
Вариант: только изменяемая ссылка:
fn borrow_example() {
let mut s = String::from("hello");
let r2 = &mut s;
println!("{}", r2);
}
Коротко об правилах владения/заимствования:
- Каждое значение имеет единственного владельца.
- Заимствования: либо ровно 1 \,1\,1 изменяемая ссылка, либо любое количество неизменяемых ссылок одновременно.
- Изменяемая ссылка требует, чтобы переменная была объявлена `mut`.
- Заимствования живут в своей области видимости — нельзя брать изменяемую ссылку, пока ещё живёт неизменяемая, которая ссылается на то же значение.