我可以这样做:
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);
}
但我更愿意这样做:
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);
}
第二个示例没有使用错误编译:未解析的名称bar
。
在我的任务中,我可以通过一次递归来完成它,但它看起来不会很清楚。
有没有人有任何其他建议?
答案 0 :(得分:3)
我有一个相互递归闭包的解决方案,但它并没有使用多个可变借用,所以我无法将它扩展到你的例子。
有一种方法可以使用定义相互递归闭包,使用类似于单this answer单递归的方法。你可以将闭包放在一个结构中,每个结构都借用该结构作为额外的参数。
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));
}
答案 1 :(得分:2)
虽然在某些情况下定义相互递归闭包是可行的,正如Alex Knauth的回答所证明的那样,但我认为您通常不应该采用这种方法。它是不透明的,在另一个答案中指出了一些局限性,并且由于它在运行时使用特征对象和动态调度而导致性能开销。
Rust中的闭包可以认为是具有关联结构的函数,这些结构存储了您关闭的数据。因此,更通用的解决方案是定义您自己的结构以存储要关闭的数据,并在该结构上定义方法而不是闭包。对于这种情况,代码如下所示:
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);
}
虽然它比闭包更冗长,并且需要一些更明确的类型注释,但它更灵活,更易于阅读,所以我通常会喜欢这种方法。