Unable to create a local function because “can't capture dynamic environment in a fn item”

前端 未结 1 1449
梦如初夏
梦如初夏 2021-02-19 00:52

Is there any way to create a local function like this Python code?

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


        
1条回答
  •  囚心锁ツ
    2021-02-19 01:50

    Functions in Rust don't capture variables from the surrounding environment, period. A "local" function in Rust is really just a global function that isn't globally visible; it can't do anything more than any other global function.

    Instead, Rust has closures which are distinct from functions in that they do capture variables from their environment. That would look like this:

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

    Three things to note with this. Firstly, append is not what you want, you want push. You should check the documentation for Vec to see what's available and what methods do. Secondly, you have to make a mutable because it's mutating something it captured (see also this answer about Fn, FnMut, and FnOnce). Third, it won't compile:

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

    The problem is that by creating the closure, you had to give it a mutable borrow to ff. However, that borrow prevents anyone else from moving or otherwise messing with ff. You need to shorten the length of time this borrow exists:

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

    This works, but is kinda clunky. It's also unnecessary; the above could more cleanly be rewritten by just passing the borrow to ff into a local function explicitly:

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

    This last one is the best (if you're able to use it), because it keeps it clean when and why ff is being borrowed.

    0 讨论(0)
提交回复
热议问题