我正在尝试构建一个解析器,该解析器可以递归搜索从根目录(由用户传递)开始的文件系统,并解析其中的文件/目录。
我有一个目录结构,其中包含对已解析对象的引用。解析的对象保存在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/