A.B.
A.B.

Reputation: 16630

Passing a closure to a recursive function

I'm working on a quad tree. Using a closure to determine when a region should be split seems like a good idea.

pub fn split_recursively(&mut self, f: |Rect| -> bool) {
    ...
    self.children.as_mut().map(|children| {
        children.nw.split_recursively(f);
        children.ne.split_recursively(f);
        children.sw.split_recursively(f);
        children.se.split_recursively(f);
    });
}

The above is what I have tried, but I get

error: cannot move out of captured outer variable

children.se.split_recursively(f);

For each of the four children.

I then tried wrapping the closure in a RefCell

fn split_recursively(&mut self, f: &RefCell<|Rect| -> bool>)

and calling it

let should_split = (*f.borrow_mut())(self.rect);

but Rust doesn't like that either:

error: closure invocation in a & reference

I know how to work around this by passing a function pointer and &mut to a rng (because splitting should in part depend on randomness), but a closure would be more elegant. Is there any way to get this to work with a closure? If not, would it be possible with unboxed closures?

Upvotes: 3

Views: 1898

Answers (1)

Austin B
Austin B

Reputation: 1600

Unboxed closures do work but they are currently feature-gated and add complexity.

#![feature(unboxed_closures)]
use std::ops::Fn;

fn main() {
    let f = |&: x: uint| println!("Recurse {}!", x);

    recursive(&f, 0);
}

fn recursive(f: &Fn<(uint,), ()>, depth: uint) {
    if depth < 10 {
        f.call((depth,)); // Cannot be invoked like f(depth) currently.
        recursive(f, depth + 1);
    } else {
        ()
    }
}

(Rust-Playpen link)

Searching around, I found an easy solution. Just call the closure in a closure:

fn main() {
    let f = |x: uint| println!("Recurse {}!", x);

    recursive(f, 0);
}

fn recursive(f: |uint| -> (), depth: uint) {
    if depth < 10 {
        f(depth);
        recursive(|x| f(x), depth + 1);
    } else {
        ()
    }
}

(Rust-Playpen link)

This has a performance impact compared to unboxed closures but it's definitely easier to read. Your choice.

Upvotes: 5

Related Questions