Невозможно вернуть вектор строковых фрагментов: заимствованное значение не живет достаточно долго

Я новичок в Rust и у меня возникли проблемы с проверкой заимствований. Я не понимаю, почему этот код не скомпилируется. Извините, если это близко к ранее отвеченному вопросу, но я не могу найти решение в других вопросах, на которые я смотрел.

Я понимаю сходство сВозврат локальной строки в виде среза (& str) но в этом случае возвращается только одна строка, и мне недостаточно рассуждать с моим кодом, в котором я пытаюсь вернуть вектор. Из того, что я понимаю, я пытаюсь вернуть ссылки наstr типы, которые выйдут из области видимости в конце функционального блока, и поэтому я должен отображать этот вектор&str в векторString? Я не так обеспокоен влиянием производительности преобразования&str вString, Сначала я бы хотел, чтобы все заработало.

Это код, ошибка вlex функция.

use std::io::prelude::*;
use std::fs::File;
use std::env;

fn open(mut s: &mut String, filename: &String) {
    let mut f = match File::open(&filename) {
        Err(_) => panic!("Couldn't open file"),
        Ok(file) => file,
    };
    match f.read_to_string(&mut s) {
        Err(_) => panic!("Couldn't read file"),
        Ok(_) => println!("File read successfully"),
    };

}

fn lex(s: &String) -> Vec<&str> {
    let token_string: String = s.replace("(", " ( ")
        .replace(")", " ) ");

    let token_list: Vec<&str> = token_string.split_whitespace()
        .collect();
    token_list
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        panic!("Please provide a filename");
    } else {
        let ref filename = args[1];

        let mut s = String::new();
        open(&mut s, filename);
        let token_list: Vec<&str> = lex(&s);
        println!("{:?}", token_list);
    }
}

Вот сообщение об ошибке

error: borrowed value does not live long enough
        self.0.borrow().values.get(idx)
        ^~~~~~~~~~~~~~~
reference must be valid for the anonymous lifetime #1 defined on the block at 23:54...
    pub fn value(&self, idx: usize) -> Option<&Value> {
                                                      ^
note: ...but borrowed value is only valid for the block at 23:54
    pub fn value(&self, idx: usize) -> Option<&Value> {
                                                      ^

Мне трудно рассуждать с этим кодом, потому что с моим уровнем опыта работы с Rust я не могу представить время жизни этих переменных. Буду признателен за любую помощь, поскольку я потратил час или два, пытаясь понять это.

 Alex G10 авг. 2016 г., 11:07
Должен ли я определить строку вне функции и передать изменяемую ссылку, или есть способ продлить время жизни строки, определенной внутри функции, чтобы она могла пережитьlex функционировать?
 Shepmaster10 авг. 2016 г., 14:11
Дубликат будетstackoverflow.com/q/29428227/155423; но у вас может быть немного времени, чтобы все изменилось.
 oli_obk10 авг. 2016 г., 11:09
Вы не можете продлить всю жизнь, никогда. У меня есть решение вашей проблемы, но вам нужно изменить свой вопрос, если вы не хотите, чтобы он был помечен как дубликат. Он должен учитывать, почему он отличается от всех других вопросов, которые задают, как вернуть ссылки на принадлежащий объект.
 oli_obk10 авг. 2016 г., 11:03
Вы смотрели на любой другой вопрос "x не живет достаточно долго" stackoverflow? Вы создаете новыйString вlex функция, а затем пытается вернуть ссылки в этоStringхотя этоString не переживаетlex функция, так что ваши ссылки будут указывать в пустоту.

Ответы на вопрос(1)

Решение Вопроса

Проблема в том, что вы выделяете новыйString (token_string) внутриlex функция, а затем возвращает массив ссылок на него, ноtoken_string будет сброшен (и память освободится), как только он выйдет из области видимости в конце функции.

fn lex(s: &String) -> Vec<&str> {
    let token_string: String = s.replace("(", " ( ") // <-- new String allocated 
        .replace(")", " ) "); 

    let token_list: Vec<&str> = token_string.split_whitespace()
        .collect();
    token_list // <-- this is just an array of wide pointers into token_string
} // <-- token_string gets freed here, so the returned pointers
  //     would be pointing to memory that's already been dropped!

Есть несколько способов решить эту проблему. Можно было бы заставить вызывающегоlex передать в буфер, который вы хотите использовать для сбора в. Это изменит подпись наfn lex<'a>(input: &String, buffer: &'a mut String) -> Vec<&'a str> Эта подпись будет указывать, что время жизни возвращенного&strs будет, по крайней мере, равным времени жизни буфера, который был передан.

Другим способом было бы просто вернутьVec<String> вместоVec<&str> если вы можете терпеть дополнительные ассигнования.

 Ben Marten12 янв. 2019 г., 08:29
Отличный ответ, спасибо!
 Alex G14 авг. 2016 г., 06:22
Спасибо за вашу помощь. Это имеет большой смысл сейчас.

Ваш ответ на вопрос