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

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

问题描述

当我遇到这个有趣的场景时,我正在玩 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().

推荐答案

短版

闭包f 存储对y 的可变引用.如果允许返回此引用的副本,您最终会同时获得两个对 y 的可变引用(一个在闭包中,一个返回),这是 Rust 的内存安全规则所禁止的.

Short version

The closure f stores a mutable reference to y. If it were allowed to return a copy of this reference, you would end up with two simultaneous mutable references to y (one in the closure, one returned), which is forbidden by Rust's memory safety rules.

闭包可以被认为是

struct __Closure<'a> {
    y: &'a mut i32,
}

因为它包含一个可变引用,所以闭包被称为FnMut,本质上与定义

Since it contains a mutable reference, the closure is called as FnMut, essentially with the definition

fn call_mut(&mut self, args: ()) -> &'a mut i32 { self.y }

因为我们只有一个对闭包本身的可变引用,所以我们不能将字段 y 从借用的上下文中移出,我们也不能复制它,因为可变引用不是复制.

Since we only have a mutable reference to the closure itself, we can't move the field y out of the borrowed context, neither are we able to copy it, since mutable references aren't Copy.

我们可以通过强制闭包被调用为 FnOnce 而不是 FnMut 来欺骗编译器接受代码.此代码工作正常:

We can trick the compiler into accepting the code by forcing the closure to be called as FnOnce instead of FnMut. This code works fine:

fn main() {
    let x = String::new();
    let mut y: u32 = 10;
    let f = || {
        drop(x);
        &mut y
    };
    f();
}

由于我们在闭包的作用域内消费了x并且x不是Copy,所以编译器检测到闭包只能是FnOnce.调用 FnOnce 闭包通过值传递闭包本身,因此我们可以将可变引用移出.

Since we are consuming x inside the scope of the closure and x is not Copy, the compiler detects that the closure can only be FnOnce. Calling an FnOnce closure passes the closure itself by value, so we are allowed to move the mutable reference out.

强制闭包为 FnOnce 的另一种更明确的方法是将其传递给具有 trait bound 的泛型函​​数.这段代码也能正常工作:

Another more explicit way to force the closure to be FnOnce is to pass it to a generic function with a trait bound. This code works fine as well:

fn make_fn_once<'a, T, F: FnOnce() -> T>(f: F) -> F {
    f
}

fn main() {
    let mut y: u32 = 10;
    let f = make_fn_once(|| {
        &mut y
    });
    f();
}

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

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