为什么我不能从闭包中返回对外部变量的可变引用? [英] Why can I not return a mutable reference to an outer variable from a closure?

查看:194
本文介绍了为什么我不能从闭包中返回对外部变量的可变引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我遇到这个有趣的场景时,我正在玩Rust闭包:

I was playing around with Rust closures when I hit this interesting scenario:

fn main() {
    let mut y = 10;

    let f = || &mut y;

    f();
}

这给出了一个错误:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
 --> src/main.rs:4:16
  |
4 |     let f = || &mut y;
  |                ^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime  as defined on the body at 4:13...
 --> src/main.rs:4:13
  |
4 |     let f = || &mut y;
  |             ^^^^^^^^^
note: ...so that closure can access `y`
 --> src/main.rs:4:16
  |
4 |     let f = || &mut y;
  |                ^^^^^^
note: but, the lifetime must be valid for the call at 6:5...
 --> src/main.rs:6:5
  |
6 |     f();
  |     ^^^
note: ...so type `&mut i32` of expression is valid during the expression
 --> src/main.rs:6:5
  |
6 |     f();
  |     ^^^

即使编译器试图逐行解释它,我仍然不明白它到底在抱怨什么.

Even though the compiler is trying to explain it line by line, I still haven't understood what exactly it is complaining about.

是否要说可变引用不能超过封闭的闭包?

Is it trying to say that the mutable reference cannot outlive the enclosing closure?

如果删除调用f(),编译器不会抱怨.

The compiler does not complain if I remove the call f().

推荐答案

这里有两个主要方面:

  1. 封闭不能返回对其环境的引用
  2. 对可变引用的可变引用只能使用外部引用的生存期(与不变引用不同)


关闭返回对环境的引用

闭包不能返回有效期为self (闭包对象)的任何引用.这是为什么?每个闭包都可以称为FnOnce,因为这是FnMut的超级特征,而这又是Fn的超级特征. FnOnce具有此方法:


Closures returning references to environment

Closures cannot return any references with the lifetime of self (the closure object). Why is that? Every closure can be called as FnOnce, since that's the super-trait of FnMut which in turn is the super-trait of Fn. FnOnce has this method:

fn call_once(self, args: Args) -> Self::Output;

请注意,self是按值传递的.因此,由于self已被消耗(并且现在位于call_once函数中),我们无法返回对其的引用-等同于返回对局部函数变量的引用.

Note that self is passed by value. So since self is consumed (and now lives within the call_once function`) we cannot return references to it -- that would be equivalent to returning references to a local function variable.

理论上,call_mut将允许返回对self的引用(因为它接收到&mut self).但是,由于call_oncecall_mutcall都是用同一主体实现的,因此闭包通常不能返回对self的引用(即:对其捕获的环境的引用).

In theory, the call_mut would allow to return references to self (since it receives &mut self). But since call_once, call_mut and call are all implemented with the same body, closures in general cannot return references to self (that is: to their captured environment).

只需确保:闭包可以捕获引用并将其返回!他们可以通过引用捕获,并返回该引用.那些事情有些不同.它与闭包类型中存储的内容有关.如果类型中存储了引用,则可以将其返回.但是我们不能返回对封闭类型中存储的任何内容的引用.

Just to be sure: closures can capture references and return those! And they can capture by reference and return that reference. Those things are something different. It's just about what is stored in the closure type. If there is a reference stored within the type, it can be returned. But we can't return references to anything stored within the closure type.

考虑此功能(请注意,参数类型暗示'inner: 'outer'outer'inner短):

Consider this function (note that the argument type implies 'inner: 'outer; 'outer being shorter than 'inner):

fn foo<'outer, 'inner>(x: &'outer mut &'inner mut i32) -> &'inner mut i32 {
    *x
}

这不会编译.乍一看,它似乎应该编译,因为我们只是剥离了一层引用.它确实适用于不可变的引用!但是此处可变的引用在保留健全性方面有所不同.

This won't compile. On the first glance, it seems like it should compile, since we're just peeling one layer of references. And it does work for immutable references! But mutable references are different here to preserve soundness.

不过,可以返回&'outer mut i32.但是要获得更长(内部)寿命的直接参考是不可能的.

It's OK to return &'outer mut i32, though. But it's impossible to get a direct reference with the longer (inner) lifetime.

让我们尝试编写您要编写的闭包代码:

Let's try to hand code the closure you were trying to write:

let mut y = 10;

struct Foo<'a>(&'a mut i32);
impl<'a> Foo<'a> {
    fn call<'s>(&'s mut self) -> &'??? mut i32 { self.0 }
}

let mut f = Foo(&mut y);
f.call();

返回的引用应具有哪个生存期?

What lifetime should the returned reference have?

  • 不能为'a,因为我们基本上有一个&'s mut &'a mut i32.并且如上所述,在这种嵌套的可变参考情况下,我们无法提取更长的寿命!
  • 但是它也不可以是's,因为那将意味着闭包返回的生存期为'self(从self借用").而且如上所述,闭包无法做到这一点.
  • It can't be 'a, because we basically have a &'s mut &'a mut i32. And as discussed above, in such a nested mutable reference situation, we can't extract the longer lifetime!
  • But it also can't be 's since that would mean the closure returns something with the lifetime of 'self ("borrowed from self"). And as discussed above, closures can't do that.

因此,编译器无法为我们生成闭包impls.

So the compiler can't generate the closure impls for us.

这篇关于为什么我不能从闭包中返回对外部变量的可变引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆