В Rust представлен код: fn borrow_str() -> &String { let s = String::from(\"hi\"); &s }\nПочему он не компилируется; объясните модель владения и заимствований и предложите несколько способов исправить функцию

17 Мар в 08:37
11 +1
0
Ответы
1
Проблема: функция возвращает ссылку на локальную переменную. Код
```rust
fn borrow_str() -> &String {
let s = String::from("hi");
&s
}
```
не компилируется, потому что `s` удалится (drop) при выходе из функции, а возвращаемая ссылка станет висячей. Компилятор сообщает примерно: “returns a reference to data owned by the current function”.
Коротко о модели владения и заимствований:
- Каждый ресурс (например, `String`) имеет одного владельца. Когда владелец выходит из области видимости — ресурс освобождается.
- Ссылка `&T` или `&mut T` заимствует ресурс у владельца; сама ссылка не продлевает время жизни значения.
- За lifetimes (времена жизни ссылок) следит borrow checker: нельзя вернуть ссылку, чей lifetime короче, чем ожидаемый lifetime возвращаемого значения.
- Чтобы вернуть ссылку, источник должен жить дольше вызывающего (например, быть передан в функцию или иметь `'static` lifetime).
Варианты исправления (с пояснениями):
1) Вернуть сам `String` (передать владение):
```rust
fn borrow_str() -> String {
let s = String::from("hi");
s
}
```
Плюс: просто и безопасно — вызывающий получает владение.
2) Вернуть строковый литерал с `'static` lifetime:
```rust
fn borrow_str() -> &'static str {
"hi"
}
```
Строковый литерал живёт всё время выполнения программы, поэтому ссылка безопасна.
3) Вернуть ссылку, но принимать источник извне (аннотировать lifetime):
```rust
fn borrow_str(s: &'a String) -> &'a String {
s
}
// или более обобщённо
fn borrow_str_str(s: &'a str) -> &'a str {
s
}
```
Здесь функция не создаёт значение, а лишь возвращает ссылку на переданный объект; borrow checker проверит, что источник живёт достаточно долго.
4) Вернуть умный указатель (разделяемое владение):
```rust
use std::rc::Rc;
fn borrow_str() -> Rc {
Rc::new(String::from("hi"))
}
// или для многопоточности: std::sync::Arc
```
Выдаёт владельца-обёртку, которую можно клонировать для совместного владения.
5) Вернуть Box (передать владение на куче):
```rust
fn borrow_str() -> Box {
Box::new(String::from("hi"))
}
```
Box тоже передаёт владение, но значение хранится на куче.
6) (Хак) Утечка в `'static` — небезопасно в общем случае, но работает:
```rust
fn borrow_str() -> &'static String {
let s = Box::leak(Box::new(String::from("hi")));
s
}
```
Это делает `String` пожизненным (утечёт память) — использовать с осторожностью.
Вывод: нельзя возвращать ссылку на локальную переменную. Выберите подходящий паттерн: возвращать владение (`String`, `Box`, `Rc/Arc`) или ссылку на внешний ресурс (передать его в функцию и использовать lifetime-параметр), либо использовать литерал с `'static`.
17 Мар в 08:43
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир