How to define mutual recursion with closures?

↘锁芯ラ 提交于 2020-06-08 19:02:48

问题


I can do something like this:

fn func() -> (Vec<i32>, Vec<i32>) {
    let mut u = vec![0;5];
    let mut v = vec![0;5];

    fn foo(u: &mut [i32], v: &mut [i32], i: usize, j: usize) {
        for k in i+1..u.len() {
            u[k] += 1;
            bar(u, v, k, j);
        }
    }
    fn bar(u: &mut [i32], v: &mut [i32], i: usize, j: usize) {
        for k in j+1..v.len() {
            v[k] += 1;
            foo(u, v, i, k);
        }
    }
    foo(&mut u, &mut v, 0, 0);
    (u,v)
}

fn main() {
    let (u,v) = func();
    println!("{:?}", u);
    println!("{:?}", v);
}

but I would prefer to do something like this:

fn func() -> (Vec<i32>, Vec<i32>) {
    let mut u = vec![0;5];
    let mut v = vec![0;5];

    let foo = |i, j| {
        for k in i+1..u.len() {
            u[k] += 1;
            bar(k, j);
        }
    };
    let bar = |i, j| {
        for k in j+1..v.len() {
            v[k] += 1;
            foo(i, k);
        }
    };
    foo(0, 0);
    (u,v)
}

fn main() {
    let (u,v) = func();
    println!("{:?}", u);
    println!("{:?}", v);
}

The second example doesn't compile with the error: unresolved name bar. In my task I can do it through one recursion, but it will not look clear. Does anyone have any other suggestions?


回答1:


I have a solution for mutually recursive closures, but it doesn't work with multiple mutable borrows, so I couldn't extend it to your example.

There is a way to use define mutually recursive closures, using an approach similar to how this answer does single recursion. You can put the closures together into a struct, where each of them takes a borrow of that struct as an extra argument.

fn func(n: u32) -> bool {
    struct EvenOdd<'a> {
        even: &'a Fn(u32, &EvenOdd<'a>) -> bool,
        odd: &'a Fn(u32, &EvenOdd<'a>) -> bool
    }
    let evenodd = EvenOdd {
        even: &|n, evenodd| {
            if n == 0 {
                true
            } else {
                (evenodd.odd)(n - 1, evenodd)
            }
        },
        odd: &|n, evenodd| {
            if n == 0 {
                false
            } else {
                (evenodd.even)(n - 1, evenodd)
            }
        }
    };
    (evenodd.even)(n, &evenodd)
}

fn main() {
    println!("{}", func(5));
    println!("{}", func(6));
}



回答2:


While defining mutually recursive closures works in some cases, as demonstrated in the answer by Alex Knauth, I don't think that's an approach you should usually take. It is kind of opaque, has some limitations pointed out in the other answer, and it also has a performance overhead since it uses trait objects and dynamic dispatch at runtime.

Closures in Rust can be thought of as functions with associated structs storing the data you closed over. So a more general solution is to define your own struct storing the data you want to close over, and define methods on that struct instead of closures. For this case, the code could look like this:

pub struct FooBar {
    pub u: Vec<i32>,
    pub v: Vec<i32>,
}

impl FooBar {
    fn new(u: Vec<i32>, v: Vec<i32>) -> Self {
        Self { u, v }
    }

    fn foo(&mut self, i: usize, j: usize) {
        for k in i+1..self.u.len() {
            self.u[k] += 1;
            self.bar(k, j);
        }
    }

    fn bar(&mut self, i: usize, j: usize) {
        for k in j+1..self.v.len() {
            self.v[k] += 1;
            self.foo(i, k);
        }
    }
}

fn main() {
    let mut x = FooBar::new(vec![0;5], vec![0;5]);
    x.foo(0, 0);
    println!("{:?}", x.u);
    println!("{:?}", x.v);
}

(Playground)

While this can get slightly more verbose than closures, and requires a few more explicit type annotations, it's more flexible and easier to read, so I would generally prefer this approach.



来源:https://stackoverflow.com/questions/34847890/how-to-define-mutual-recursion-with-closures

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!