async fn 调用 split 产生错误 "borrowed value does not live long enough"
async fn calling split generates error "borrowed value does not live long enough"
我创建了一个人为的示例来理解我在使用 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
看运行住在playground
完成相同任务的非异步代码工作正常(参见 playground):
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
}
您的 non-async 翻译不正确。如果将 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()
returns Option<io::Result<String>>
, and the String
is dropped at the end of each loop turn. However, str::trim()
and str::split()
使用 &str
并生成 &str
具有相同的生命周期(因为它们只对字符串进行切片,而不是更改它)。因此,您将 h
推入一个 &str
并具有一个循环周期的生命周期,即悬空引用。
它与 str::lines()
is that std::str::Lines::next()
returns Option<&str>
一起工作的原因是引用与原始 &str
相关联,即 'static
.
解决这个问题的最简单方法是将 &str
转换为拥有的 String
:
h.insert(word.to_owned(), true);
我创建了一个人为的示例来理解我在使用 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
看运行住在playground
完成相同任务的非异步代码工作正常(参见 playground):
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
}
您的 non-async 翻译不正确。如果将 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()
returns Option<io::Result<String>>
, and the String
is dropped at the end of each loop turn. However, str::trim()
and str::split()
使用 &str
并生成 &str
具有相同的生命周期(因为它们只对字符串进行切片,而不是更改它)。因此,您将 h
推入一个 &str
并具有一个循环周期的生命周期,即悬空引用。
它与 str::lines()
is that std::str::Lines::next()
returns Option<&str>
一起工作的原因是引用与原始 &str
相关联,即 'static
.
解决这个问题的最简单方法是将 &str
转换为拥有的 String
:
h.insert(word.to_owned(), true);