recursion - 使用可变引用对app_state进行递归更新更新

标签 recursion rust reference borrow-checker

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

我有一个目录结构,其中包含对已解析对象的引用。解析的对象保存在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);
            }

        }
    }

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

有人可以照亮发生的事情,以便我更好地理解吗?

最佳答案

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

关于recursion - 使用可变引用对app_state进行递归更新更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62364880/

相关文章:

rust - 什么时候需要使用生命周期?

c++ - 具有 get 函数的模板类总是返回引用,

Java StringBuffer 扩展后不会更改引用

python - 实现模式匹配 - 何时使用缓存?

JavaScript - 通过对象递归循环

java - 递归:检查目录中的文件并读取它们

PHP 数组语法解析错误左方括号 "["

c++ - 递归函数总是返回假

json - serde_json::from_str 错误,其中字符串来自文件

rust - Arc、thread 和 channel 的借用值不够长