Как использовать ссылку на замыкание FnOnce? - PullRequest
0 голосов
/ 02 февраля 2019

У меня есть функция, которая должна рекурсивно передавать аргумент замыкания

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,
        }
    }
}

Это не работает:

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

Если я пытаюсь изменить тип f с f: F до f: &F Я получаю ошибку компилятора

error[E0507]: cannot move out of borrowed content
  --> src/lib.rs:22:17
   |
22 |                 f(node.borrow().val);
   |                 ^ cannot move out of borrowed content

Как мне обойти это?

Я вызываю функцию следующим образом:

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 Ответ

0 голосов
/ 02 февраля 2019

FnOnce является наиболее общим функциональным ограничением.Однако это означает, что ваш код должен работать для всех возможных функций, включая те, которые используют их среду.Вот почему он называется FnOnce: единственное, что вы о нем знаете, это то, что его можно назвать хотя бы один раз, но не обязательно больше.Внутри pre_order мы можем только предполагать, что истинно для каждого возможного F: его можно вызвать один раз.

Если вы измените его на Fn или FnMut, наИсключив замыкания, которые используют их окружение, вы сможете вызывать его несколько раз.FnMut является следующей наиболее общей чертой функции, поэтому предпочтительно принять ее вместо Fn, чтобы убедиться, что вы можете принять большинство функций:

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,
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...