我正在尝试为一些 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));
}
}
}
我相信在这种情况下你无论如何都不应该使用入口 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));
}
}