简体   繁体   English

Rust 使用可变引用递归更新 app_state

[英]Rust recursive updates to app_state with mutable reference

I'm trying to build a parser that can recursively search a file system starting at a root directory (that is passed in by the user) and parse the files / directories within.我正在尝试构建一个解析器,它可以递归地搜索从根目录(由用户传入)开始的文件系统并解析其中的文件/目录。

I have a Directory struct that holds references to parsed objects.我有一个目录结构,其中包含对已解析对象的引用。 Parsed Objects are held in HashMaps which are part of a State struct.解析的对象保存在 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>,
}

I have an app_state struct that holds all hash maps, like this (some hash maps omitted for brevity):我有一个 app_state 结构,其中包含所有 hash 映射,如下所示(为简洁起见,省略了一些 hash 映射):

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

The Parser::parse signature looks like this: Parser::parse签名如下所示:

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

When Parser::parse is called it is passed a &PathBuf for the root directory.当 Parser::parse 被调用时,它会传递一个 &PathBuf 用于根目录。 Each entry in the root directory will be looked at with two possibilities:根目录中的每个条目都将以两种可能性进行查看:

The entry is a directory: ===> 1) Create a new directory object.入口是一个目录:===> 1)创建一个新目录object。 2) Save the directory object into the correct directory_hash . 2) 将目录 object 保存到正确的directory_hash中。 3) Parse the directory by calling the Parser::parse again with this as the root directory, and passing the app_state that we are currently using. 3) 通过再次调用Parser::parse来解析目录,并以此为根目录,并传递我们当前使用的 app_state。

The entry is a file of some type: ===> 1) Parse the file into an object of the correct type.该条目是某种类型的文件:===> 1) 将文件解析为正确类型的 object。 2) Save the file into the correct hash map on app_state. 2) 将文件保存到 app_state 上正确的 hash map 中。 3) Save a reference to it into the Vector on the current directory object. 3) 将对其的引用保存到当前目录 object 上的 Vector 中。

Problem : because this will recursively be called for anything with a depth greater than 1, I can't pass app_state to the Parser::parse method mutably again.问题:因为这将递归地调用任何深度大于 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)

Where I'm most stuck : This only occurs when I try to store REFERENCES in the vectors that live on the Directory struct.我最卡住的地方:这只发生在我尝试将 REFERENCES 存储在 Directory 结构上的向量中时。 If I were to store actual instances of those objects, this recursive call doesn't error.如果我要存储这些对象的实际实例,则此递归调用不会出错。 But I want to store everything in the master app_state object and only reference the rest from elsewhere.但我想将所有内容存储在主app_state object 中,并且只从其他地方引用 rest。

Here's what my Parser::parse code looks like:这是我的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);
            }

        }
    }

Can someone please help me with this issue?有人可以帮我解决这个问题吗? I've tried the suggestions that the compiler gives with adding lifetimes which in simpler situations I understand, but here I am either getting "doesn't live long enough" or "can't borrow mutably more than once" errors.我已经尝试了编译器给出的添加生命周期的建议,这些建议在我理解的更简单的情况下,但在这里我要么得到“活得不够长”或“不能多次可变地借用”错误。

Can someone illuminate what's happening so I can better understand?有人可以阐明正在发生的事情,以便我更好地理解吗?

This approach is inherently memory-unsafe: for instance, as the directory_hash grows, at some point its hash table will be rebuilt with different physical locations for the Directory entries, which would leave dangling references in the child_dirs entries.这种方法本质上是内存不安全的:例如,随着directory_hash的增长,在某些时候,它的 hash 表将使用Directory条目的不同物理位置重建,这将在child_dirs条目中留下悬空引用。 Rust will not allow this, so there is no way to solve this problem by adding/modifying the lifetimes annotations. Rust 不允许这样做,因此无法通过添加/修改生命周期注释来解决此问题。 Instead, a different way of structuring the data is needed.相反,需要一种不同的数据结构方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM