【问题标题】:Unable to create a local function because "can't capture dynamic environment in a fn item"无法创建本地函数,因为“无法在 fn 项中捕获动态环境”
【发布时间】:2017-08-11 06:12:27
【问题描述】:

有没有办法像这样的 Python 代码创建一个本地函数?

def h():
    final = []
    def a():
        for i in range(5):
            final.append(i)
        a()
        return final

我试过了,但失败了:

fn h() -> Vec<i32> {
    let mut ff = vec![];
    fn a() {
        for i in 0..5 {
            ff.push(i)
        }
    };
    a();
    ff
}
 error[E0434]: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
 --> src/main.rs:5:13
  |
5 |             ff.push(i)
  |             ^^

【问题讨论】:

    标签: function rust


    【解决方案1】:

    Rust 中的函数不会从周围环境中捕获变量。 Rust 中的“本地”函数实际上只是一个全局函数,它不是全局可见的。它不能做比任何其他全局函数更多的事情。

    相反,Rust 具有与函数不同的闭包,因为它们确实从其环境中捕获变量。看起来像这样:

    fn h() -> Vec<i32> {
        let mut ff = vec![];
        let mut a = || {
            for i in 0..5{
                ff.push(i)
            }
        };
        a();
        ff
    }
    

    这有三点需要注意。首先,append 不是你想要的,你想要的是push。您应该检查documentation for Vec 以查看可用的方法和方法。其次,你必须使a 可变,因为它正在改变它捕获的东西(另见answer about Fn, FnMut, and FnOnce)。第三,它不会编译:

    error[E0505]: cannot move out of `ff` because it is borrowed
     --> <anon>:9:9
      |
    3 |         let mut a = || {
      |                     -- borrow of `ff` occurs here
    ...
    9 |         ff
      |         ^^ move out of `ff` occurs here
    

    问题在于,通过创建闭包,您必须向ff 提供一个可变借用。但是,这种借用可以防止其他任何人移动或以其他方式弄乱ff。您需要缩短此借用存在的时间长度:

    fn h() -> Vec<i32> {
        let mut ff = vec![];
        {
            let mut a = || {
                for i in 0..5{
                    ff.push(i)
                }
            };
            a();
        }
        ff
    }
    

    这可行,但有点笨重。这也是不必要的;只需将借用 ff 显式传递给本地函数,就可以更干净地重写上述内容:

    fn h() -> Vec<i32> {
        let mut ff = vec![];
        fn a(ff: &mut Vec<i32>) {
            for i in 0..5{
                ff.push(i)
            }
        }
        a(&mut ff);
        ff
    }
    

    最后一个是最好的(如果您能够使用它),因为它可以在何时以及为何借用 ff 时保持干净。

    【讨论】:

    • 我想知道我是否可以在闭包中写一个递归?如果不是,有没有什么办法让ff不是参数,而是在函数a中提到的,并且函数a能够递归?
    • @EvaRed 正如我所说,函数不会捕获。 期间。 至于递归,闭包没有名字,所以不能自递归。即使他们可以,我也不确定它是否适用于正在进行的隐性借款。如果您真的非常迫切地需要使用闭包进行递归,您可能可以使用蹦床使其工作(借用问题),但这将是一个不同的问题。
    • @EvaRed 我可能应该注意到,蹦床方法最终可能会显着比仅使用函数并显式传递 &amp;mut ff 更加复杂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    相关资源
    最近更新 更多