Needless to say, it can also be done in today’s rust closures. Only that you will need a fixed point combinator, like the following.
Playground link
fn fix<F,T,R>(f:F, t:T) -> R
where F: FnOnce(&Fn(T) -> R, T) -> R + Clone
{
(f.clone())(&|t| fix(f.clone(), t), t)
}
fn main(){
let fib = |i|fix(move |s:&Fn((u32,u32,u32)) -> u32, v:(u32,u32,u32)|
match v.0 {
0 => v.1,
1 => v.2,
i => s((i-1, v.2,v.1+v.2))
}, (i,1,1));
println!("{}",fib(46));
}
Compare to the solution in the top post, this is less intuitive and harder for new users. Moreover, it depends on the fact that u32 is Copy and so mutation can be simulated. But for other types, this may not be that easy and may need to introduce Cell or RefCell things.
All I want to see for this feature, is not to change anything that works today, it is to allow a new way to express the same intention. So if you don’t like it, don’t use it! This apply to @H2CO3 's refactoring argument, and the
@MajorBreakfast 's FnBox argument. (and actually, if we do need FnBox, my proposal is an improvement because the user have full access to the Box and the closure code can decide to move the content out of the box, which would not be allowed in today’s rust closures)
When talking about real usage, well, it is depending on how would you define “complicated”. In the fib case, it seems easy to have a separated function. But this applies to all closures, if you always prefer to have separately defined functions, why do you need a closure? But then closure was proved its value in all modern programming languages.
Having said that, let me just try to give another use case though. Let’s say that an application will listen on a port for connections. It only handles one connection at a time, but each time it receives a connection and handles it, it changes the way it authenticate the client.
let mut password = gen_password();
accept_client(listen_socket, move |mut self, client| {
handle(client, &self.password);
next_password(&mut self.password);
accept_client(self.listen_socket, self)
});
As I have said, you can decide to not use the self part and you don’t have to use self in the body, so you can extract the function easily. But even with self you can still do it like this:
let mut password = gen_password();
accept_client(listen_socket, move |mut self, client| {
let closure = self;
handle(client, &closure.password);
next_password(&mut closure.password);
accept_client(closure.listen_socket, closure);
});