Дан фрагмент на Rust: let r; { let x = 5; r = &x; } println!("{}", r); Объясните, почему этот код не компилируется, какие правила владения и времени жизни нарушаются и как правильно передать данные наружу
Код не компилируется потому, что `r` становится ссылкой на локальную переменную `x`, которая уничтожается при выходе из внутреннего блока — получается висячая (dangling) ссылка. Компилятор выдаст ошибку вида: “borrowed value does not live long enough”. Правила владения и времени жизни, которые нарушаются: - Ссылке нельзя жить дольше значения, на которое она ссылается. Нужно, чтобы время жизни `x` было не короче времени жизни `r`: ′x≥′r 'x \ge 'r ′x≥′r. В вашем коде ′x'x′x (время жизни `x`) короче ′r'r′r, поэтому заимствование недопустимо. - Rust запрещает возвращать/хранить ссылку на локальную переменную, потому что это нарушает безопасность памяти. Как правильно передать данные наружу (варианты): 1) Передать значение (move или copy). Для простых типов (например, 555 — тип `i32`, `Copy`) можно просто переместить/скопировать значение: let r; { let x = 5; r = x; // копия значения, ничего не умирает при выходе из блока } println!("{}", r); Для несopiруемых типов (например, String) можно выполнить move: let r; { let s = String::from("hello"); r = s; // ownership перемещается в r } println!("{}", r); 2) Выделить в куче и переместить владение (Box/Rc/Arc): let r; { let b = Box::new(5); r = b; // Box перемещён наружу } println!("{}", r); 3) Использовать статическое значение, если уместно: static X: i32 = 5; let r = &X; // &'static i32 println!("{}", r); 4) Возвращать ссылку только если она ссылается на данные, живущие дольше (например, параметр функции): fn choose(x: &'a i32) -> &'a i32 { x } Коротко: либо передавайте владение (move/Box/Rc), либо делайте ссылку на данные с подходящей (длинной) временем жизни; нельзя держать ссылку на переменную, которая уже выходит из области видимости.
Правила владения и времени жизни, которые нарушаются:
- Ссылке нельзя жить дольше значения, на которое она ссылается. Нужно, чтобы время жизни `x` было не короче времени жизни `r`: ′x≥′r 'x \ge 'r ′x≥′r. В вашем коде ′x'x′x (время жизни `x`) короче ′r'r′r, поэтому заимствование недопустимо.
- Rust запрещает возвращать/хранить ссылку на локальную переменную, потому что это нарушает безопасность памяти.
Как правильно передать данные наружу (варианты):
1) Передать значение (move или copy). Для простых типов (например, 555 — тип `i32`, `Copy`) можно просто переместить/скопировать значение:
let r;
{
let x = 5;
r = x; // копия значения, ничего не умирает при выходе из блока
}
println!("{}", r);
Для несopiруемых типов (например, String) можно выполнить move:
let r;
{
let s = String::from("hello");
r = s; // ownership перемещается в r
}
println!("{}", r);
2) Выделить в куче и переместить владение (Box/Rc/Arc):
let r;
{
let b = Box::new(5);
r = b; // Box перемещён наружу
}
println!("{}", r);
3) Использовать статическое значение, если уместно:
static X: i32 = 5;
let r = &X; // &'static i32
println!("{}", r);
4) Возвращать ссылку только если она ссылается на данные, живущие дольше (например, параметр функции):
fn choose(x: &'a i32) -> &'a i32 { x }
Коротко: либо передавайте владение (move/Box/Rc), либо делайте ссылку на данные с подходящей (длинной) временем жизни; нельзя держать ссылку на переменную, которая уже выходит из области видимости.