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

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

Я понимаю сходство с Return local String как среза (&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 я не могу представить время жизни этих переменных. Буду признателен за любую помощь, поскольку я потратил час или два, пытаясь понять это.

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> если вы можете терпеть дополнительные ассигнования.

Другие вопросы по тегам