Recursive closures is possible in Rust, but it cannot mutate its captured variables as to make it recursive it have to keep a separate reference of the closure itself.
I am thinking a way to get around this restriction and make recursion easier. Like this:
let mut i1 = 1;
let mut i2 = 1;
let fib: &FnOnce(i:i32) -> i32 = &move |mut captured,i|
match i {
0 => i1,
1 => i2,
i => {
(captured.i1, captured.i2) =
(captured.i2, captured.i1 + captured.i2);
captured(i-1)
}
}
};
We make captured work as self in impl blocks, and making it the closure itself. we can also allow it to be decorated like &captured, &mut captured etc. If captured appears in the variables, it have to be the first one, and every access to the captured variable must have captured. prefix.
Note: The move keyword is not necessary here as in the above example we receive captured by value, so it forces to move everything captured to the closure.
The move keyword is still needed as in the above case we have option to copy or move. But move will be redundant in cases when there are any captured variable is not Copy.
Once we have this we may need to relax the Fn trait structure to allow Fn not necessary FnMut and FnMut not necessary FnOnce, because once we use the above syntax, the result type will have only one Trait being implemented, and it may not be an easy task to generate other variations for calling.
Of cause, for backward compatibility we will not change anything if the first variable of the closure is not captured, and the result closure will have FnOnce if only FnMut is needed, FnMut if only Fn is needed, as usual. And there is no prefix when accessing captured variables.
Another benefit of this is it supports FnBox the same way as others:
let mut i1 = 1;
let mut i2 = 1;
let fib: Box<FnBox(i:i32) -> i32> = box move |mut box captured,i|
match i {
0 => i1,
1 => i2,
i => {
(captured.i1, captured.i2) =
(captured.i2, captured.i1 + captured.i2);
captured(i-1)
}
}
};
Even when we later decided to make Box<FnOnce> just work, stabilizing FnBox is still a good option as it makes the above works the same way as the other variants. EDIT (Except that we might want to remove the closure grammar we use today being able to generate FnBox automatically. This means if you still want to use FnBox you have add box self in the parameter list, explicitly.)
It is too early to formalize this into a RFC, I am just want to see how people feel about this.
