简体   繁体   English

使用可变的“self”引用调用方法时的生命周期错误

[英]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:此错误消息中有许多我不明白的地方:

  • Where is the "autoref" happening here?这里发生的“autoref”在哪里?
  • Which lifetime is being referred to when it says "first, the lifetime cannot outlive the lifetime '_ as defined here..."?当它说“首先,生命周期不能超过这里定义的生命周期'_ _......”时,指的是哪个生命周期? Does the closure implicitly create a lifetime for itself?闭包是否隐含地为自己创建了一个生命周期?
  • Where it says "so that the types are compatible" - In what way exactly are the types not currently compatible?它在哪里说“以便类型兼容” - 类型当前不兼容的确切方式是什么?

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.

相关问题 Rust - 生命周期 - 了解对自身的可变引用的生命周期错误 - Rust - Lifetimes - Understanding Lifetime Error for mutable reference to self 从闭包调用可变方法时无法推断 autoref 的生命周期 - Cannot infer lifetime for autoref when calling mutable method from closure 如何解决生存期错误以在Rust中进行可变引用? - How to resolve lifetime error for mutable reference in Rust? 当我在结构中使用可变引用而不是不可变引用时,为什么会出现生命周期错误? - Why do I get a lifetime error when I use a mutable reference in a struct instead of an immutable reference? 从 trait 方法返回对结构字段的可变引用时,如何修复生命周期不匹配? - How do I fix the lifetime mismatch when returning a mutable reference to the struct's field from a trait method? 创建可变迭代器时出现生命周期错误 - Lifetime error when creating mutable iterator 将可变引用与 self 映射时存在冲突的生命周期要求 - Conflicting lifetime requirements when mapping mutable references with self 如何将可变自引用传递给特征方法? - How to pass a mutable self reference on to a trait method? 将可变的自引用传递给拥有对象的方法 - Passing mutable self reference to method of owned object 具有可变引用的递归结构中的生命周期 - Lifetime in recursive struct with mutable reference
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM