简体   繁体   中英

return a recursive closure which move environmental mutable variable into it from a function?

Ways that make recursive closure are not suitable for me from the accepted answer of the question:

Is it possible to make a recursive closure in Rust?

My closure need to be returned from a function and need to move variable from the environment into it, and can mutate it.

Then I find a way seems more suitable for me:

Anonymous recursion with closures

use std::cell::RefCell;

fn main() {
    let id = &(|a| a) as &Fn(u64) -> u64;
    let (fib, fib_p): (_, RefCell<&Fn(u64) -> u64>);
    fib_p = RefCell::new(id);

    fib = |n: u64| {
        if n < 2 {
            n
        } else {
            (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
        }
    };

    *fib_p.borrow_mut() = &fib;

    println!("{}", fib(10));        
}

The above code works fine.

But my closure need to be returned from a function, so it can't be a reference to prevent dangling Reference, and we don't know the size of the closure from compile time, so I used the smart pointer Box for it. The below code throws an error:

use std::cell::RefCell;

fn main() {
    let id: Box<Fn(u64) -> u64> = Box::new(|a| a);
    let (fib, fib_p): (Box<Fn(u64) -> u64>, RefCell<&Box<Fn(u64) -> u64>>);
    fib_p = RefCell::new(&id);

    fib = Box::new(|n: u64| {
        if n < 2 {
            n
        } else {
            (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
        }
    });

    *fib_p.borrow_mut() = &fib;

    println!("{}", fib(10));        
}
error[E0597]: `fib_p` does not live long enough
  --> src/main.rs:12:15
   |
8  |     fib = Box::new(|n: u64| {
   |                    -------- capture occurs here
...
12 |             (&fib_p.borrow())(n - 2) + (&fib_p.borrow())(n - 1)
   |               ^^^^^ borrowed value does not live long enough
...
19 | }
   | - borrowed value dropped before borrower
   |
   = note: values in a scope are dropped in the opposite order they are created

You can wrap your recursive context in a non recursive closure:

pub fn fib() -> Box<Fn(u64) -> u64> {
    Box::new(|n: u64| {
        let id = &(|a| a) as &Fn(u64) -> u64;
        let (fib, fib_p): (_, RefCell<&Fn(u64) -> u64>);
        fib_p = RefCell::new(id);

        fib = |n: u64| {
            if n < 2 {
                n
            } else {
                (fib_p.borrow())(n - 2) + (fib_p.borrow())(n - 1)
            }
        };

        *fib_p.borrow_mut() = &fib;

        fib(n)
    })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM