Rust - 将空条目插入 HashMap 的可变借用问题

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

我正在尝试为一些 yml 配置文件(使用 serde)编写一个简单的解析器,其中涉及对许多参数内的自定义格式进行一些额外的解析。我的附加解析器基于简单的正则表达式,并且我创建了一个注册表,以便它们仅“编译”一次。注册表本质上是一个

HashMap<String, _>
。 当然,现在注册正则表达式的方法首先通过
HashMap::entry()
方法检查是否已插入相同的正则表达式。

问题是,如果我写这样的东西:

    fn register_pattern(&mut self, pattern: &str) {
        if let Vacant(entry) = self.regex_registry.entry(pattern.to_string()) {
            let asc = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Ascii);
            let jap = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Japanese);
            let parse_localized_regex = ...expression involving asc, jap...;
        }
    }

...编译器这样对我大喊大叫:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/parsing/parsers/parser_service.rs:65:23
   |
63 |         if let Vacant(entry) = self.regex_registry.entry(pattern.to_string()) {
   |                                ------------------- first mutable borrow occurs here
64 |             let asc = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Ascii);
65 |             let jap = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Japanese);
   |                       ^^^^ second mutable borrow occurs here
66 |             let parse_localized_regex = ParseLocalized::new(asc, jap);
67 |             entry.insert(parse_localized_regex);
   |             ----- first borrow later used here

我找到的解决方案有效,但对我来说似乎太复杂了:

    fn register_pattern(&mut self, pattern: &str) {
        if let Vacant(_) = self.regex_registry.entry(pattern.to_string()) {
            let asc = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Ascii);
            let jap = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Japanese);
            if let Vacant(entry) = self.regex_registry.entry(pattern.to_string()) {
                entry.insert(ParseLocalized::new(asc, jap));
            }
        }
    }
rust borrow-checker
1个回答
0
投票

我相信在这种情况下你无论如何都不应该使用入口 API - 即使不考虑这个问题。

这是因为入口 API 为了能够在丢失密钥时插入密钥,需要拥有一个拥有的密钥。对你来说,这意味着你不能使用

&str
进行查找,你必须调用
to_string()
- 这意味着分配,这比第二次查找的成本更大,并且假设(据我所知)大多数情况下该模式已经注册,分配的成本将使双重查找的成本相形见绌。

因此,最适合您的解决方案是使用简单的结构:

    fn register_pattern(&mut self, pattern: &str) {
        if !self.regex_registry.contains(pattern) {
            let asc = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Ascii);
            let jap = self.parse_locale_pattern(pattern.to_string(), ParseLocale::Japanese);
            let parse_localized_regex = ...expression involving asc, jap...;

            self.regex_registry.insert(pattern.to_string(), ParseLocalized::new(asc, jap));
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.