Search code examples
genericsrustiteratorclosures

Can you return closures or create callable objects that behave like cloosures?


There's a problem I keep running into. Say for example I have the following:

fn make_iterator<'a, T>(t: &'a T) -> ///???
where T: SomeTrait
{
 /* some complex logic*/
  
   return |i:usize| {
      let res = t.method(i);
      t.other_method(res)
   };
}

A practical example of something like this I am trying:

    pub fn iter_concentric_rings<'a>(&'a self, depth: usize)
    where
        V: Clone + Debug,
        E: Clone + Debug,
        F: Clone + Debug,
    {
        BFSIterator::new(self.id(), |depth, &id| {
            let v = unsafe { (*self.mesh).vert_handle(id) };
            v.iter_verts().map(|h| h.id())
        })
    }

in either of these cases, the objective is constructing a closure that does something with context it inherits from the broader scope. They exist as a convenience, the caller could simply just define them themselves, it's just tedious and verbose.

You could replace them with macros, and that would work, but I tend to prefer avoiding macros when possible.

If structs were callable you could instead define the functionality as a method of a struct and pass that, allowing you to return a closure like object that is not a closure.

In general, I just don't know how to make these helpers that try to minimize the tedium of defining common patterns of closure definition that are constructed all over my code.


Solution

  • You can use impl Trait syntax to return a closure.

    pub fn return_closure<T>(t: T) -> impl FnOnce(usize) -> T {
        move |i: usize| t
    }
    

    You may want to return FnOnce, FnMut, or Fn depending on the closure.

    Your other example will likely look something like this:

    pub fn iter_concentric_rings<'a>(&'a self, depth: usize)
        -> BFSIterator<impl Fn(usize, &Id) -> IterVerts + 'a>
    

    You can't make structs callable, but you can make another trait and implement it for closures and certain structs.