reference - 为什么我不能从闭包中返回对外部变量的可变引用?

标签 reference rust closures lifetime mutable

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

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();
  |     ^^^

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

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

如果删除调用f(),编译器不会提示。

最佳答案

这里有两个主要的作用:

  • 闭包无法返回对其环境的引用
  • 对可变引用的可变引用只能使用外部引用的生存期(与不可变引用不同)


    闭包返回对环境的引用

    闭包不能返回self (闭包对象)的生存期的任何引用。这是为什么?每个闭包都可以称为FnOnce,因为那是FnMut的 super 特征,而这又是Fn的 super 特征。 FnOnce具有此方法:
    fn call_once(self, args: Args) -> Self::Output;
    

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

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

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

    嵌套可变引用

    考虑一下此函数(请注意,参数类型暗含'inner: 'outer'outer'inner短):
    fn foo<'outer, 'inner>(x: &'outer mut &'inner mut i32) -> &'inner mut i32 {
        *x
    }
    

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

    不过,可以返回&'outer mut i32。但是,要获得更长(内部)生命周期的直接引用是不可能的。

    手动编写闭包

    让我们尝试编写您要编写的闭包代码:
    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();
    

    返回的引用应具有什么生命周期?
  • 不能是'a,因为我们基本上有一个&'s mut &'a mut i32。如上所述,在这种嵌套的可变引用情况下,我们无法提取更长的生命周期!
  • 但这也不能是's,因为这将意味着闭包在'self的生命周期内返回某些内容(“从self借用”)。而且如上所述,闭包不能做到这一点。

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

    关于reference - 为什么我不能从闭包中返回对外部变量的可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65584936/

    相关文章:

    rust - 匹配武器 : "mismatched types expected (), found integral variable"

    network-programming - 如何使用 UdpSocket 接收任意长度的数据?

    Jquery,从函数访问变量

    c# - C# 中用于捕获委托(delegate)的循环反汇编的无用变量?

    C++ 常量引用生命周期(容器适配器)

    python - 对在 python 中将列表项分配给 vars 感到困惑

    reference - ABAP中的#符号是什么?

    loops - 如何遍历递归/嵌套 HashMap 中的所有键?

    ios - Swift Closure 中的可选链接,其中返回类型必须为 Void

    c# - 你能让一个元素和一个列表中的元素表现得像同一个对象吗?