Я создал надуманный пример, чтобы понять ошибку, которую я вижу с асинхронной функцией, используя tokio:
pub async fn unique_words_async() -> io::Result<u32> {
let file = File::open("sample.txt").await?;
let reader = BufReader::new(file);
let mut lines = reader.lines();
let mut h = HashMap::new();
h.insert("word", true);
while let Some(line) = lines.next_line().await? {
let mut split = line.trim().split(' ');
while let Some(word) = split.next() {
h.insert(word, true);
}
}
Ok(h.len() as u32)
}
вот точная ошибка:
16 | let mut split = line.trim().split(' ');
| ^^^^^^^^^^^ borrowed value does not live long enough
...
20 | }
| - `line` dropped here while still borrowed
21 | Ok(h.len() as u32)
| ------- borrow later used here
смотрите бег в прямом эфире в детская площадка
Неасинхронный код для выполнения той же задачи отлично работает (см. детская площадка):
pub fn unique_words() -> u32 {
let input = "this is one line\nhere is another line";
let mut lines = input.lines();
let mut h = std::collections::HashMap::new();
while let Some(line) = lines.next() {
let mut split = line.split(' ');
while let Some(word) = split.next() {
h.insert(word, true);
}
}
h.len() as u32
}
Ваш неасинхронный перевод неверен. Если вы будете использовать File
с BufReader
, у вас будет та же ошибка:
pub fn unique_words() -> std::io::Result<u32> {
use std::io::BufRead;
let file = std::fs::File::open("sample.txt")?;
let reader = std::io::BufReader::new(file);
let mut lines = reader.lines();
let mut h = std::collections::HashMap::new();
while let Some(line) = lines.next().transpose()? {
let mut split = line.split(' ');
while let Some(word) = split.next() {
h.insert(word, true);
}
}
Ok(h.len() as u32)
}
error[E0597]: `line` does not live long enough
--> src/main.rs:10:25
|
10 | let mut split = line.split(' ');
| ^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
14 | }
| - `line` dropped here while still borrowed
15 | Ok(h.len() as u32)
| ------- borrow later used here
Это связано с тем, что Lines::next()
возвращает Option<io::Result<String>>
, а String
отбрасывается в конце каждого цикла цикла. Однако str::trim()
и str::split()
берут &str
и производят &str
с тем же временем жизни (поскольку они только нарезают строку, а не изменяют ее). Таким образом, вы вставляете h
a &str
со временем жизни в один цикл, то есть висячую ссылку.
Причина, по которой это работало с str::lines()
, заключается в том, что std::str::Lines::next()
возвращает Option<&str>
со ссылкой, привязанной к исходному &str
, то есть 'static
.
Самый простой способ исправить это — преобразовать &str
в собственный String
:
h.insert(word.to_owned(), true);