这可能是我不了解借阅检查器的一些技术性的教科书案例,但如果有人能为我解决这个问题会很好。
我有这段(非常简化的)代码,编译得非常好。
pub struct Example(pub Vec<String>);
impl Example {
pub fn iter(&self) -> impl Iterator<Item=&String> {
self.0.iter()
}
}
pub fn some_condition(_: &str) -> bool {
// This is not important.
return false;
}
pub fn foo() -> bool {
let example = Example(vec!("foo".to_owned(), "bar".to_owned()));
let mut tmp = example.iter();
tmp.all(|x| some_condition(x))
}
pub fn main() {
println!("{}", foo());
}
但是,我尝试的第一件事(在我看来,应该与上面的相同)是省略临时变量 tmp
一共如下pub fn foo() -> bool {
let example = Example(vec!("foo".to_owned(), "bar".to_owned()));
example.iter().all(|x| some_condition(x))
}
但是这个版本会产生以下错误。error[E0597]: `example` does not live long enough
--> so_temporary.rs:23:3
|
23 | example.iter().all(|x| some_condition(x))
| ^^^^^^^-------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
24 | }
| -
| |
| `example` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `impl std::iter::Iterator`
|
= note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.
现在,显然,错误末尾的注释是一个很好的建议,这就是我引入临时解决问题的原因。但我不明白为什么这可以解决问题。我的 tmp
的生命周期有何不同?变量与 example.iter()
直接嵌入到表达式中,使一项工作,一项失败?
最佳答案
这与 Why do I get "does not live long enough" in a return value? 的答案基本相同并且它在错误本身中有所解释,但我会详细说明。此行为与普通 block 表达式相同:
pub struct Example(pub Vec<String>);
impl Example {
pub fn iter(&self) -> impl Iterator<Item=&String> {
self.0.iter()
}
}
pub fn main() {
let foo = {
let example = Example(vec!("foo".to_owned(), "".to_owned()));
example.iter().all(String::is_empty)
};
println!("{}", foo);
}
error[E0597]: `example` does not live long enough
--> src/main.rs:12:9
|
12 | example.iter().all(String::is_empty)
| ^^^^^^^-------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
13 | };
| -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `impl Iterator`
| |
| `example` dropped here while still borrowed
|
= note: the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
12 | let x = example.iter().all(String::is_empty); x
| ^^^^^^^ ^^^
scope of temporary values通常是创建它们的语句。在上面的代码中 example
是一个变量,它在 block 的末尾被销毁。但是,example.iter()
创建一个临时 impl Iterator
它的临时范围是完整的let foo = ...
陈述。因此,评估时的步骤是:example.iter().all(...)
的结果example
foo
impl Iterator
您可能会看到这可能出错的地方。引入变量的原因是因为它迫使任何临时对象更快地被删除。谈函数时,情况略有不同,但效果是一样的:
Temporaries that are created in the final expression of a function body are dropped after any named variables bound in the function body, as there is no smaller enclosing temporary scope.
关于评论:
impl Iterator
时起作用的原因替换为 std::slice::Iter<'_, i32>
(在 pretzelhammer 的例子中)是因为 drop checker 知道 slice::Iter
不访问 example
下降,而它必须假设 impl Iterator
做。fn my_all(mut self, ...)
的原因(在 Peter Hall 的例子中)是因为 all
通过引用获取迭代器,但 my_all
按值(value)计算。临时impl Iterator
在表达式结束之前被消耗和销毁。通过查看与此相关的各种 Rust 问题,很明显有些人会认为这是一个错误。
{ ...; EXPR }
绝对不明显和 { ...; let x = EXPR; x }
可能会有所不同。但是,由于添加了诊断和文档来加强和解释这种行为,我不得不假设这些临时范围规则允许更合理的代码。
关于rust - 为什么 "the temporary is part of an expression at the end of a block"是一个错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65972165/