Передача итератора в рекурсивный вызов во время итерации в Rust - PullRequest
0 голосов
/ 06 февраля 2020

Я пишу парсер для простого синтаксиса дерева. При этом мне нужно построить дерево из серии токенов.

В основе кода в настоящее время лежит проблема с проверкой заемщика:

use std::vec;

fn parse_iter(token_iter: vec::IntoIter<Token>) -> Result<Vec<Node>, String>
{
    let mut nodes: Vec<Node> = vec![];
    let mut cur_node: Option<Node> = None;
    for token in token_iter {
        match token {
            Token::ParenOpen => {
                if let Some(mut node) = cur_node {
                    let mut children = parse_iter(token_iter)?;
                    node.children.append(&mut children);
                } else {
                    return Err("invalid token sequence".to_string());
                }
            }
            Token::ParenClose => {
                break;
            }
            Token::Name(name) => {
                let node = Node::new(name);
                nodes.push(node);
                cur_node = Some(node);
            }
            Token::Comma => {}
        }
    }
    Ok(nodes)
}


pub enum Token {
    ParenOpen,
    ParenClose,
    Comma,
    Name(String),
}

pub struct Node {
    pub name: String,
    pub children: Vec<Node>,
}

impl Node {
    pub fn new<'a>(name: String) -> Node {
        Node { name: name, children: vec![] }
    }
}

Возникшая ошибка сообщения:

   Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value
  --> src/lib.rs:10:29
   |
10 |                 if let Some(mut node) = cur_node {
   |                             ^^^^^^^^ value moved here, in previous iteration of loop
   |
   = note: move occurs because value has type `Node`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `token_iter`
  --> src/lib.rs:11:60
   |
3  | fn parse_iter(token_iter: vec::IntoIter<Token>) -> Result<(Vec<Node>, vec::IntoIter<Token>), String>
   |               ---------- move occurs because `token_iter` has type `std::vec::IntoIter<Token>`, which does not implement the `Copy` trait
...
7  |     for token in token_iter {
   |                  ----------
   |                  |
   |                  value moved here
   |                  help: consider borrowing to avoid moving into the for loop: `&token_iter`
...
11 |                     let mut children_and_iter = parse_iter(token_iter)?;
   |                                                            ^^^^^^^^^^ value moved here, in previous iteration of loop

error[E0382]: use of moved value: `node`
  --> src/lib.rs:23:33
   |
21 |                 let node = Node::new(name);
   |                     ---- move occurs because `node` has type `Node`, which does not implement the `Copy` trait
22 |                 nodes.push(node);
   |                            ---- value moved here
23 |                 cur_node = Some(node);
   |                                 ^^^^ value used here after move

Как вы можете видеть выше, и token_iter, и cur_node несколько раз перемещаются нелегально в этой функции, и я не уверен, как правильно их обернуть, чтобы удовлетворить проверку заимствования , Я пытался использовать RefCell<Rc<T>> s, но в конечном итоге мне нужно развернуть значения, чтобы они не помогли. Возможно ли то, что я пытаюсь сделать в Rust?

1 Ответ

1 голос
/ 06 февраля 2020

Я считаю плохой идеей повторять for token in token_iter и , пытаясь оперировать на token_iter внутри l oop. Таким образом, я предлагаю взять token_iter как &mut и выполнить итерацию вручную.

Кроме того, наличие как cur_node, так и nodes кажется избыточным (если я не ошибаюсь, cur_node по существу nodes.last). Таким образом, я бы попробовал следующее:

use std::vec;

fn parse_iter(token_iter: &mut vec::IntoIter<Token>) -> Result<(Vec<Node>, &mut vec::IntoIter<Token>), String>
{
    let mut nodes: Vec<Node> = vec![];
    while let Some(token)=token_iter.next() {
        match token {
            Token::ParenOpen => {
                if let Some(ref mut node) = nodes.last_mut() {
                    let mut children_and_iter = parse_iter(token_iter)?;
                    node.children.append(&mut children_and_iter.0);
                } else {
                    return Err("invalid token sequence".to_string());
                }
            }
            Token::ParenClose => {
                break;
            }
            Token::Name(name) => {
                nodes.push(Node::new(name));
            }
            Token::Comma => {}
        }
    }
    Ok((nodes, token_iter))
}


pub enum Token {
    ParenOpen,
    ParenClose,
    Comma,
    Name(String),
}

pub struct Node {
    pub name: String,
    pub children: Vec<Node>,
}

impl Node {
    pub fn new<'a>(name: String) -> Node {
        Node { name: name, children: vec![] }
    }
}
...