[英]lifetime error when calling method with mutable `self` reference
Here is the code in question:这是有问题的代码:
struct CodeGenerator;
struct Command<'a> {
command: &'a String,
}
struct Expression;
impl CodeGenerator {
fn compile_push_arguments<'a>(
&'a mut self,
arguments: &'a Vec<Expression>,
) -> Vec<Command<'a>> {
arguments
.into_iter()
.flat_map(|argument| self.compile_expression(argument))
.collect()
}
fn compile_expression<'a>(&'a mut self, expression: &'a Expression) -> Vec<Command<'a>> {
todo!()
}
}
This produces the following compile error:这会产生以下编译错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:14:39
|
14 | .flat_map(|argument| self.compile_expression(argument))
| ^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/main.rs:14:23
|
14 | .flat_map(|argument| self.compile_expression(argument))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `self`
--> src/main.rs:14:34
|
14 | .flat_map(|argument| self.compile_expression(argument))
| ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:8:31
|
8 | fn compile_push_arguments<'a>(
| ^^
note: ...so that the types are compatible
--> src/main.rs:12:9
|
12 | / arguments
13 | | .into_iter()
14 | | .flat_map(|argument| self.compile_expression(argument))
15 | | .collect()
| |______________________^
= note: expected `Vec<Command<'a>>`
found `Vec<Command<'_>>`
For more information about this error, try `rustc --explain E0495`.
There are a number of things I don't understand in this error message:此错误消息中有许多我不明白的地方:
'_
as defined here..."?'_
_......”时,指的是哪个生命周期? Does the closure implicitly create a lifetime for itself? Basically, I want to understand the error.基本上,我想了解错误。
I noticed that removing the mut
from the reference to self fixes it, but I'm not sure why.我注意到从对 self 的引用中删除
mut
可以修复它,但我不知道为什么。
Where is the "autoref" happening here?
这里发生的“autoref”在哪里?
Autoref happens when you invoke a method.调用方法时会发生自动引用。 See this question for more information.
有关更多信息,请参阅此问题。
I noticed that removing the
mut
from the reference to self fixes it, but I'm not sure why.我注意到从对 self 的引用中删除
mut
可以修复它,但我不知道为什么。
This is actually the problem.这实际上是问题所在。 Your other questions kind of skirt around it, so I'm going to table them for a moment to explain why omitting
mut
makes it all work.你的其他问题有点绕了它,所以我将把它们放在桌子上,解释一下为什么省略
mut
会让一切正常。
Recall that returning a reference from a function extends the borrow given to the function.回想一下,从 function 返回一个引用扩展了对 function 的借用。 This is obvious when the types of references match:
当引用类型匹配时,这一点很明显:
fn a<'x>(foo: &'x i32) -> &'x i32 { todo!(); }
fn b<'x>(foo: &'x mut i32) -> &'x mut i32 { todo!(); }
We know that whatever borrow we give the function is extended through the return value.我们知道,我们给 function 的任何借用都是通过返回值扩展的。 It's less obvious what happens when the mutability of the references disagree:
当引用的可变性不一致时会发生什么就不太明显了:
fn c<'x>(foo: &'x mut i32) -> &'x i32 { todo!(); }
A naive conclusion is that the input borrow is "downgraded" but that isn't the case -- the mutable borrow is extended through the immutable reference that is returned.一个天真的结论是输入借用被“降级”,但事实并非如此——可变借用通过返回的不可变引用进行扩展。 Here is a concrete example:
这是一个具体的例子:
fn downgrade<'x>(foo: &'x mut i32) -> &'x i32 { foo }
fn main() {
let mut i = 0i32;
let i_ref = downgrade(&mut i);
let i_ref_2 = downgrade(&mut i);
println!("{} {}", i_ref, i_ref_2);
}
You might expect this to compile, but it does not.您可能希望它能够编译,但事实并非如此。
i_ref
extends the mutable borrow, which prevents i
from being borrowed mutably (or even immutably.) a second time i_ref
扩展了可变借用,这可以防止i
被可变地(甚至不可变地)第二次借用。
error[E0499]: cannot borrow `i` as mutable more than once at a time
--> src/main.rs:6:29
|
5 | let i_ref = downgrade(&mut i);
| ------ first mutable borrow occurs here
6 | let i_ref_2 = downgrade(&mut i);
| ^^^^^^ second mutable borrow occurs here
7 |
8 | println!("{} {}", i_ref, i_ref_2);
| ----- first borrow later used here
Once you understand that this doesn't compile, it should be more apparent why your code doesn't compile with mut
.一旦你明白这不能编译,你的代码为什么不能用
mut
编译就应该更清楚了。 Look at the declaration of compile_expression
:查看
compile_expression
的声明:
fn compile_expression<'a>(
&'a mut self,
expression: &'a Expression
) -> Vec<Command<'a>>
{ todo!(); }
This is doing exactly the same thing, but it's obfuscated a bit.这是做完全相同的事情,但它有点混淆了。
Vec<Command<'a>>
refers to 'a
which means it extends the mutable borrow of self
. Vec<Command<'a>>
指的是'a
,这意味着它扩展了self
的可变借用。 That's a problem for the closure given to flat_map()
because it might be called more than once -- the Vec<Command<'a>>
returned from the prior iteration needs to be dropped before the closure can be invoked again.这是给
flat_map()
的闭包的问题,因为它可能被多次调用——从先前迭代返回的Vec<Command<'a>>
需要在闭包被再次调用之前被删除。 It's effectively the same basic problem as in the simpler example I gave above, but with a more confusing diagnostic from the compiler.这实际上与我上面给出的更简单示例中的基本问题相同,但编译器的诊断更加混乱。 (Note this would be an issue even without the
.collect()
invocation. This closure, when given to flat_map()
, creates a lifetime situation that the Iterator
trait cannot express. It's akin to the "owning iterator" problem .) (请注意,即使没有
.collect()
调用,这也是一个问题。这个闭包,当给flat_map()
时,会创建Iterator
trait 无法表达的生命周期情况。它类似于“拥有迭代器”问题。)
Removing mut
makes it work since the borrow extended by the closure isn't exclusive.删除
mut
使其工作,因为闭包扩展的借用不是独占的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.