【发布时间】:2020-03-12 02:47:07
【问题描述】:
作为一项教育练习,我正在考虑将 cvs-fast-export 移植到 Rust。
它的基本操作方式是将多个CVS主文件解析成一个中间形式,然后对中间形式进行分析,目的是将其转化为git快速导出流。
解析时要做的一件事是将中间形式的公共部分转换为规范表示。一个鼓舞人心的例子是提交作者。一个 CVS 存储库可能有数十万个单独的文件提交,但可能少于一千个作者。因此,当您从文件中解析作者时,在解析输入作者的位置时使用了一个实习表,它会给您一个指向规范版本的指针,如果以前没有见过它,则会创建一个新版本。 (我也听说过这叫做雾化或实习)。然后这个指针被存储在中间对象上。
我第一次尝试在 Rust 中做类似的事情是尝试使用 HashSet 作为实习表。注意这里使用的是 CVS 版本号而不是作者,这只是一个数字序列,例如 1.2.3.4,表示为 Vec。
use std::collections::HashSet;
use std::hash::Hash;
#[derive(PartialEq, Eq, Debug, Hash, Clone)]
struct CvsNumber(Vec<u16>);
fn intern<T:Eq + Hash + Clone>(set: &mut HashSet<T>, item: T) -> &T {
let dupe = item.clone();
if !set.contains(&item) {
set.insert(item);
}
set.get(&dupe).unwrap()
}
fn main() {
let mut set: HashSet<CvsNumber> = HashSet::new();
let c1 = CvsNumber(vec![1, 2]);
let c2 = intern(&mut set, c1);
let c3 = CvsNumber(vec![1, 2]);
let c4 = intern(&mut set, c3);
}
error[E0499]: cannot borrow 'set' as mutable more than once at a time 失败。这很公平,HashSet 不保证如果您在获得参考后添加更多项目,对其键的参考将有效。 C 版本小心地保证这一点。为了得到这个保证,我认为HashSet 应该超过Box<T>。但是我无法向借阅检查器解释这个的生命周期。
我在这里使用的所有权模型是实习表拥有数据的规范版本,并分发引用。只要实习表存在,引用就应该是有效的。我们应该能够在不使旧引用无效的情况下向实习表添加新内容。我认为我的问题的根源在于我很困惑如何以与 Rust 所有权模型一致的方式编写该合约的接口。
我用我有限的 Rust 知识看到的解决方案是:
- 执行两次,在第一次通过时构建
HashSet,然后将其冻结并在第二次通过时使用引用。这意味着额外的临时存储空间(有时很大)。 - 不安全
有人有更好的主意吗?
【问题讨论】:
标签: rust hashset canonicalization