Невозможно вернуть вектор срезов строки: заимствованное значение не живет достаточно долго
Я новичок в 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>
Эта подпись будет указывать, что время жизни возвращенного &str
s будет, по крайней мере, равным времени жизни буфера, который был передан.
Другим способом было бы просто вернуть Vec<String>
вместо Vec<&str>
если вы можете терпеть дополнительные ассигнования.