Страницы

Поиск по вопросам

четверг, 27 декабря 2018 г.

Как из String сделать &str (возникает ошибка времени жизни ссылки)

Написал функцию:
fn read_str<'a>() -> &'a str { let mut input = String::new(); io::stdin().read_line(&mut input).ok(); let output : &str = &input[..]; &output }
При компиляции возникает ошибка
src/main.rs:13:26: 13:31 error: `input` does not live long enough src/main.rs:13 let output : &str = &input[..]; ^~~~~ src/main.rs:10:30: 15:2 note: reference must be valid for the lifetime 'a as defined on the block at 10:29... src/main.rs:10 fn read_str<'a>() -> &'a str { src/main.rs:11 let mut input = String::new(); src/main.rs:12 io::stdin().read_line(&mut input).ok(); src/main.rs:13 let output : &str = &input[..]; src/main.rs:14 &output src/main.rs:15 } src/main.rs:11:32: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 11:31 src/main.rs:11 let mut input = String::new(); src/main.rs:12 io::stdin().read_line(&mut input).ok(); src/main.rs:13 let output : &str = &input[..]; src/main.rs:14 &output src/main.rs:15 }
Пробовал брать строку io::stdin().read_line(&mut input).ok(); в фигурные скобки, дабы ограничить &mut, но это не помогает.


Ответ

Вернуть из функции можно только ссылку на статический объект (с временем жизни 'static) или ссылку, которую вы получили во входных параметрах.
Вы пытаетесь вернуть ссылку на объект созданный в стеке функции. После завершения функции все объекты в стеке будут уничтожены. Rust не позволит создать ссылку на объект, который она может пережить. Использование после освобождения (use after free)
В вашем случае лучше всего вернуть String. Накладные расходы в этом случае невелики, так как почти вся информация внутри строки хранится в куче.

Большинство проблем начинающих писать на Rust связаны с непониманием назначения различных типов указателей. Если не вдаваться в подробности, их там можно насчитать пять штук.
Ссылки в Rust используются для передачи данных без передачи права владения. Например если у вас есть структура, в которой хранится строка:
struct Person{ name:String }
то выдавать информацию о ее содержимом лучше так:
impl Person{ pub fn get_name(&self)->&str{ &self.name } }
или можно вернуть копию строки:
pub fn get_name_clone(&self)->String{ self.name.clone() }
Но это приведет к дополнительным расходам на копирование строки. Расходы здесь возникают именно из-за копирования - вызова метода clone(), который создает вторую копию данных строки в куче, а не из-за того, что функция возвращает строку.
Можно вернуть строку из структуры без копирования:
pub fn get_name_own(self)->String{ self.name }
Но после вызова этого метода исходный объект Person перестанет существовать, так как право владения было передано.
Еще одна распространенная причина проблем - попытка хранить ссылки на другие объекты в структуре. Ссылки накладывают кучу ограничений на время жизни и мутабельность связанных объектов. Прежде чем это делать, стоит дважды подумать о возможности использования других типов указателей.

Комментариев нет:

Отправить комментарий