问题
I have a function which needs to pass a closure argument recursively
use std::cell::RefCell;
use std::rc::Rc;
pub struct TreeNode {
val: i32,
left: Option<Rc<RefCell<TreeNode>>>,
right: Option<Rc<RefCell<TreeNode>>>,
}
pub fn pre_order<F>(root: Option<Rc<RefCell<TreeNode>>>, f: F)
where
F: FnOnce(i32) -> (),
{
helper(&root, f);
fn helper<F>(root: &Option<Rc<RefCell<TreeNode>>>, f: F)
where
F: FnOnce(i32),
{
match root {
Some(node) => {
f(node.borrow().val);
helper(&node.borrow().left, f);
helper(&node.borrow().right, f);
}
None => return,
}
}
}
This doesn't work:
error[E0382]: use of moved value: `f`
--> src/lib.rs:23:45
|
22 | f(node.borrow().val);
| - value moved here
23 | helper(&node.borrow().left, f);
| ^ value used here after move
|
= note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `f`
--> src/lib.rs:24:46
|
23 | helper(&node.borrow().left, f);
| - value moved here
24 | helper(&node.borrow().right, f);
| ^ value used here after move
|
= note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
If I try changing type of f
from f: F
to f: &F
I get the compiler error
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:22:17
|
22 | f(node.borrow().val);
| ^ cannot move out of borrowed content
How can I get around this?
I am calling the function like this:
let mut node = TreeNode::new(15);
node.left = Some(Rc::new(RefCell::new(TreeNode::new(9))));
let node_option = Some(Rc::new(RefCell::new(node)));
pre_order(node_option, |x| {
println!("{:?}", x);
});
回答1:
FnOnce
is the most most general function constraint. However, that means your code must work for all possible functions, including those that consume their environment. That's why it's called FnOnce
: the only thing you know about it is that it can be called it at least once - but not necessarily more. Inside pre_order
we can only assume what is true of every possible F
: it can be called once.
If you change this to Fn
or FnMut
, to rule out closures that consume their environments, you will be able to call it multiple times. FnMut
is the next most general function trait, so it is preferred to accept that instead of Fn
, to make sure you can accept the most functions:
pub fn pre_order<F>(root: Option<Rc<RefCell<TreeNode>>>, mut f: F)
where
F: FnMut(i32),
{
helper(&root, &mut f);
fn helper<F>(root: &Option<Rc<RefCell<TreeNode>>>, f: &mut F)
where
F: FnMut(i32),
{
match root {
Some(node) => {
f(node.borrow().val);
helper(&node.borrow().left, f);
helper(&node.borrow().right, f);
}
None => return,
}
}
}
来源:https://stackoverflow.com/questions/54491654/how-to-use-a-reference-to-a-fnonce-closure