遇到此错误时,我正在解析文件中的一些字符串输入。通常,如果将一系列方法链接在一行上或将它们分成多个操作,应该不会有什么不同。然而在这里,当方法链在一行中时,它不会编译。
拆分为多个语句时我没有收到错误 like so (link to playground)
let input = std::fs::read_to_string("tst_input.txt").expect("Failed to read input");
let input = input
.lines()
.map(|l| {
let mut iter = l.split(" | ");
(
iter.next()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>(),
iter.next()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>(),
)
})
.collect::<Vec<_>>();
在单个语句中出现生命周期错误 like so (link to playground)
let input = std::fs::read_to_string("tst_input.txt")
.expect("Failed to read input")
.lines()
.map(|l| {
let mut iter = l.split(" | ");
(
iter.next()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>(),
iter.next()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>(),
)
})
.collect::<Vec<_>>()
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:2:17
|
2 | let input = std::fs::read_to_string("tst_input.txt")
| _________________^
3 | | .expect("Failed to read input")
| |_______________________________________^ creates a temporary which is freed while still in use
...
18 | .collect::<Vec<_>>();
| - temporary value is freed at the end of this statement
19 | println!("{:?}", input);
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
这两种情况应该实际上相同吗?为什么编译器以不同的方式对待它们?这可能是编译器错误吗?
最佳答案
这两种情况并不相同,因为存储的信息不同。
在 Rust 中,变量具有语义含义:它们充当存储信息的地方,更重要的是,它们定义何时销毁此信息 - 这由 Drop
trait 处理.默认情况下,drop
为超出范围的每个变量调用方法;这可以用 mem::forget
覆盖和一些其他功能,如 Box::into_raw
,但这些都是相当小众的案例。
在第一种情况下,正在读取的数据存储在 input
中String
类型的变量.此类型wraps Vec<u8>
,这implements Drop
,因此此数据在 input
时被释放超出范围。然后,第二个input
变量 is of type Vec<(Vec<&str>, Vec<&str>)>
- 你可以看到它包含一个引用,所以它是从第一个 input
借来的,所以它必须不再是源字符串。在这里,这是令人满意的 - 当然,只要您不尝试将此值返回堆栈,在这种情况下源字符串将被丢弃,并且引用将悬空。
然而,在单行版本中,字符串没有存储在任何地方——它是一个 temporary ,它在语句末尾被销毁。这就是为什么您不允许保留对它的任何引用的原因。但是,您可以通过插入 extra mapping operation 来创建拆分数据的自有版本。 :
let _: Vec<(Vec<String>, Vec<String>)> = std::fs::read_to_string("tst_input.txt")
.expect("Failed to read input")
// This iterator borrows from the temporary...
.lines()
.map(|l| {
// ...this iterator reborrows that borrow...
let mut iter = l.split(" | ");
(
iter.next()
.unwrap()
.split_whitespace()
// ...and this operation clones the source data,
// so they are copied to the new owned location,
// and not referenced anymore, so can be freely dropped
.map(str::to_owned)
.collect::<Vec<_>>(),
iter.next()
.unwrap()
.split_whitespace()
.map(str::to_owned)
.collect::<Vec<_>>(),
)
})
.collect::<Vec<_>>();
关于function - Rust 仅在拆分为多个语句时才编译方法链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70491691/