Несколько заимствований в предыдущей итерации цикла - PullRequest
3 голосов
/ 23 апреля 2019

Ниже приведен код, над которым я работаю, я изучаю путь к каталогу с очередью и хочу сохранить дерево файловой системы в моей структуре данных (перечисление Entry):

use failure::Error;
use std::collections::VecDeque;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn main() -> Result<(), Error> {
    let paths = visit_dir(Path::new(".")).map_err(Error::from)?;
    Ok(())
}

#[derive(Debug)]
enum Entry {
    Dir(PathBuf, Vec<Entry>),
    File(PathBuf),
}

impl Entry {
    fn new_dir(path: &Path) -> Entry {
        Entry::Dir(path.to_path_buf(), Vec::new())
    }

    fn new_file(path: &Path) -> Entry {
        Entry::File(path.to_path_buf())
    }

    /// Append a new Entry to self if self is a directory.
    fn push(&mut self, path: &Path) -> Option<&mut Entry> {
        if let Entry::Dir(_, ref mut content) = self {
            let entry = if path.is_dir() {
                Entry::new_dir(path)
            } else {
                Entry::new_file(path)
            };
            content.push(entry);
            return content.last_mut();
        }
        None
    }

    fn path(&self) -> &Path {
        match self {
            Entry::Dir(path, _) => path,
            Entry::File(path) => path,
        }
    }
}

fn visit_dir(root: &Path) -> io::Result<Entry> {
    let mut dir = Entry::new_dir(root);
    let mut queue = VecDeque::new();
    queue.push_back(&mut dir);

    while !queue.is_empty() {
        let parent = queue.pop_front().unwrap();
        let path = parent.path();
        if path.is_dir() {
            for entry in fs::read_dir(path)? {
                let entry = entry?;
                let path = entry.path();
                let entry = parent.push(&path).unwrap();

                if path.is_dir() {
                    queue.push_back(entry);
                }
            }
        }
    }

    Ok(dir)
}

Ссылка на Детская площадка

Я получаю ошибку:

error[E0499]: cannot borrow `*parent` as mutable more than once at a time
  --> src/main.rs:61:29
   |
61 |                 let entry = parent.push(&path).unwrap();
   |                             ^^^^^^ mutable borrow starts here in previous iteration of loop

Мои вопросы:

  • Почему именно я получаю эту ошибку?
  • Есть ли обходной путь для его решения?

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019
  • entry одалживает parent изменчиво в строке:

    let entry = parent.push(&path).unwrap();
    
  • Тогда вы не отпустите entry, потому что вы храните егов queue.Таким образом, parent все еще заимствовано, когда это вторая итерация в цикле.Это небезопасно делать.

То, что вы пытаетесь сделать, это дерево изменяемых ссылок.Это не сработает в Rust, и это вообще плохая идея.Вы должны изменить способ, которым вы хотите реализовать это.

0 голосов
/ 23 апреля 2019

Вы получаете эту ошибку, потому что у вас есть несколько изменяемых ссылок на родителя.

Первая изменяемая ссылка - через метод parent.push(&mut self, ...).И у вас есть куча изменчивых ссылок, возникающих из-за того, что каждый вызов push производит изменяемую ссылку на векторный элемент (&mut Entry).

Одним из возможных решений является введение RwLockвнутри Entry.Затем, передавая только обычные не изменяемые ссылки, вы все равно можете изменить внутренний вектор, но это вносит некоторые сложности и незначительные накладные расходы при блокировке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...