1

I read this already, but it did not help me since it was talking about specific function.

Is it possible to make a recursive closure in Rust?

What I want to do is this: pass the function and how many time will I repeat the function call, and get the function as return, so func_n(2, f)(x) works like f(f(x)).

So I wrote my code like this:

pub fn func_n<T, F: FnMut(T)> -> T>(n: u8, mut f: F) -> impl FnMut(T) -> T {
    let mut g = |x| x;
    for _ in 0..n {
        g = |x| g(f(x));
    }
    g
}

And the mismatched type error occured: it says that no two closures have the same type. The compiler suggests me to box the closure, but I don't want to do that, so I can use func_n as function directly.

I tried recursive function version too, but it occurred the same error.

So,

  1. Is it possible to do?
  2. If it is possible, how should I do?
Djd An
  • 21
  • 1
  • Why do you feel your first question is not answered exactly by the post you provided? – possum Oct 25 '22 at 09:11
  • Because it is about the specific function fact and returns the u32 value, but what I want to work with anonynous function f and returning function. – Djd An Oct 25 '22 at 09:45

1 Answers1

0

If you are brave enough and are willing to use unstable features you could define your own struct and implement FnOnce and FnMut traits for it:

#![feature(unboxed_closures)]
#![feature(fn_traits)]

use std::marker::PhantomData;
use std::ops::{FnMut, FnOnce};

pub struct FuncN<T, F> {
    n: usize,
    f: F,
    _marker: PhantomData<T>,
}

impl<T, F> FuncN<T, F>
where
    F: FnMut(T) -> T,
{
    pub fn new(n: usize, f: F) -> Self {
        Self {
            n,
            f,
            _marker: PhantomData,
        }
    }
}

impl<T, F> FnOnce<(T,)> for FuncN<T, F>
where
    F: FnMut(T) -> T,
{
    type Output = T;

    extern "rust-call" fn call_once(mut self, args: (T,)) -> Self::Output {
        let mut val = args.0;
        for _ in 0..self.n {
            val = (self.f)(val);
        }
        val
    }
}

impl<T, F> FnMut<(T,)> for FuncN<T, F>
where
    F: FnMut(T) -> T,
{
    extern "rust-call" fn call_mut(&mut self, args: (T,)) -> Self::Output {
        let mut val = args.0;
        for _ in 0..self.n {
            val = (self.f)(val);
        }
        val
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let add_one = |x: i32| x + 1;
        let mut add_five = FuncN::<i32, _>::new(5, add_one);

        assert_eq!(add_five(0), 5);
    }
}
Aleksander Krauze
  • 3,115
  • 7
  • 18