问题
我正在构建一个n-树的前序遍历,以这种方式为遍历中的每个节点执行一个闭包。
我的第一个方法是:
#[derive(Debug)]
pub struct Node<T> {
value: T,
children: Vec<Node<T>>,
}
impl<T> Node<T> {
pub fn preorder<F>(&self, mut f: F)
where
F: FnMut(&Self),
{
f(self);
self.children.iter().for_each(|child| child.preorder(f));
}
}
但是,当在foreach迭代器中调用child.preorder(f)
语句时,我遇到了一个错误。
error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
--> src/lib.rs:12:62
|
7 | pub fn preorder<F>(&self, mut f: F)
| ----- captured outer variable
...
12 | self.children.iter().for_each(|child| child.preorder(f));
| ------- ^ move occurs because `f` has type `F`, which does not implement the `Copy` trait
| |
| captured by this `FnMut` closure
我找到的解决方案
将pre-order方法的头部更改为以下内容可以完美地编译,但它在要使用的闭包上设置了一个Copy必需项,这是我根本不希望的。
pub fn preorder<F>(&self, mut f: F)
where
F: FnMut(&Self) + Copy,
我发现的另一种解决闭包上的Copy必要条件的方法是使用浸入方法,如下所示(see it in the playground):
pub struct Node<T> {
value: T,
children: Vec<Node<T>>,
}
impl<T> Node<T> {
fn preorder_immersion<F>(&self, f: &mut F)
where
F: FnMut(&Self),
{
f(self);
self.children
.iter()
.for_each(|child| child.preorder_immersion(f));
}
pub fn preorder_mut<F>(&self, mut f: F)
where
F: FnMut(&Self),
{
self.preorder_immersion(&mut f);
}
}
说真的,看起来很痛苦。基本上是因为它意味着每个遍历实现有两个方法。
我想要的
在调用pre-order方法时,如果能够做这样的事情就太好了:
let mut result = Vec::new();
node.preorder(|n| result.push(*n.value()));
而我给出的最新解决方案效果很好。
我的问题:还有更优雅的方式吗?我错过什么了吗?或者可以使用沉浸式方法吗?
1条答案
按热度按时间svmlkihl1#
就像我在前面的评论中所说的,我会使用基于
Iterator
的方法,在探索过程中,我发现这个解决方案在我看来非常优雅:我们将尚未产生的节点存储在
Vec
中,反过来,我们可以使用pop
和extend
,这应该是非常有效的。每当我们生成一个Node
时,我们将它的子节点添加到剩余的节点中。而不是像
node.preorder(your_closure_or_function)
这样使用它,你可以像node.preorder().for_each(your_closure_or_function)
一样使用它,但是为了一个额外的函数调用的小代价,你可以获得Rust中已经围绕迭代器构建的整个功能和工具集。