对具有可变引用的app_state进行递归更新

问题描述 投票:1回答:1

我正在尝试构建一个解析器,该解析器可以从根目录(由用户传递)开始递归搜索文件系统,并解析其中的文件/目录。

我有一个Directory结构,其中包含对已解析对象的引用。解析的对象保存在HashMaps中,而HashMaps是State结构的一部分。

pub struct Directory<'a> {
    pub pathname: String,
    pub child_dirs: Vec<&'a Directory<'a>>,
    pub child_files: Vec<&'a File>,
    pub child_templates: Vec<&'a Template>,
}

我有一个app_state结构,它保存所有哈希映射,例如这样(为简洁起见,省略了一些哈希映射:]

pub struct State<'a> {
    pub directory_hash: HashMap<OsString, Directory<'a>>,
    pub file_hash: HashMap<PathBuf, File>,
    pub template_hash: HashMap<PathBuf, Template>,
}

Parser::parse签名如下:

pub fn parse<'a>(root: &'a PathBuf, app_state: &'a mut app_state::State<'a>)

调用Parser :: parse时,将为根目录传递&PathBuf。将用两种可能性查看根目录中的每个条目:

该条目是一个目录:===> 1)创建一个新的目录对象。 2)将目录对象保存到正确的directory_hash中。 3)通过再次调用Parser::parse并将其作为根目录来解析目录,并传递我们当前正在使用的app_state。

该条目是某种类型的文件:===> 1)将文件解析为正确类型的对象。 2)将文件保存到app_state上正确的哈希图中。 3)将对它的引用保存到当前目录对象的Vector中。

问题:因为深度大于1的任何东西都会被递归调用,所以我无法再次将app_state可变地传递给Parser::parse方法。

cannot borrow `*app_state` as mutable more than once at a time

mutable borrow starts here in previous iteration of looprustc(E0499)

我最受困扰的地方:仅当我尝试将REFERENCES存储在Directory结构上的向量中时,才会发生这种情况。如果我要存储这些对象的实际实例,则此递归调用不会出错。但是我想将所有内容存储在主对象app_state中,并且仅从其他位置引用其余内容。

这是我的Parser::parse代码如下:

pub fn parse<'a>(root: &'a PathBuf, app_state: &'a mut app_state::State<'a>) {
        // Create a new directory object from the root
        let root_dir = Directory::new(root);

        // insert it into the directory hash
        let hash_key = root.clone().into_os_string();
        app_state.directory_hash.insert(hash_key, root_dir);

        // recurse over all entries in the directory
        let readable_dir = fs::read_dir(root);
        let readable_dir = match readable_dir {
            Ok(dir) => dir,
            Err(_e) => return, // handle errors that could occur
        };

        for item in readable_dir {
            let fpath = match item {
                Ok(file_path) => file_path,
                _ => continue, // handle errors that could occur
            };

            // if they are a directory, parse that directory
            if fpath.path().is_dir() {
                Self::parse(&fpath.path(), app_state);
            } else {
            // if not a directory, parse them according to their type
                let file_type = get_file_type(&fpath.path());
                Self::update_state(file_type, &fpath, app_state);
            }

        }
    }

有人可以帮我解决这个问题吗?我尝试了编译器给出的建议,即增加了一些生存时间,这些生存时间在我所理解的更简单的情况下是可以的,但是在这里,我要么遇到“寿命不足”,要么“不能多次多变地借用”错误。

有人可以阐明正在发生的事情,以便我更好地理解吗?

recursion rust reference borrow-checker
1个回答
2
投票

此方法本质上是内存不安全的:例如,随着directory_hash的增长,在某些时候它的哈希表将使用Directory条目的不同物理位置重建,这将在child_dirs中留下悬挂的引用条目。 Rust不允许这样做,因此无法通过添加/修改生命周期注释来解决此问题。相反,需要一种不同的数据结构方式。

© www.soinside.com 2019 - 2024. All rights reserved.