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.