for 循环 - 具有生命周期的结构 'a 不能借用为可变,因为它也被借用为不可变



我有一个结构体,它将id映射到索引,反之亦然。

struct IdMapping<'a> {
external_2_internal: HashMap<&'a str, usize>,
internal_2_external: HashMap<usize, String>,
}
impl<'a> IdMapping<'a> {
fn new() -> IdMapping<'a> {
IdMapping {
external_2_internal: HashMap::new(),
internal_2_external: HashMap::new(),
}
}
fn insert(&'a mut self, internal: usize, external: String) {
self.internal_2_external.insert(internal, external);
let mapped_external = self.internal_2_external.get(&internal).unwrap();
self.external_2_internal.insert(mapped_external, internal);
}
}

如果我这样使用这个结构

fn map_ids<'a>(ids: Vec<String>) -> IdMapping<'a> {
let mut mapping = IdMapping::new();
for (i, id) in ids.iter().enumerate() {
mapping.insert(i, id.clone());
}
mapping
}

我收到以下编译错误:

error[E0499]: cannot borrow `mapping` as mutable more than once at a time
--> src/lib.rs:28:9
|
24 | fn map_ids<'a>(ids: Vec<String>) -> IdMapping<'a> {
|            -- lifetime `'a` defined here
...
28 |         mapping.insert(i, id.clone());
|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `mapping` was mutably borrowed here in the previous iteration of the loop
...
31 |     mapping
|     ------- returning this value requires that `mapping` is borrowed for `'a`

操场上联系

为什么我不能在每次循环迭代时可变地借用它的insert方法的映射?我应该如何实现这个用例?

问题是由于你的结构中的self引用。

让我们首先看看这在理论上是否合理(假设我们正在编写不安全的代码):

  1. HashMap使用平面数组(二次探测),因此HashMap中的对象在插入新元素时地址不稳定。这意味着插入internal_2_external可能会移动内存中现有的Strings。
  2. String将其内容存储在单独的堆分配中,堆分配保持在相同的位置。所以即使String被移动了,引用它的&str仍然指向有效的内存。

因此,如果在不安全代码中实现,这实际上是可以工作的。

逻辑上的声音做这些操作,类型系统无法认识到,你可以移动String同时保持借来的有效范围。这意味着,如果您从String中借用&str,类型系统将阻止您对String执行任何突变操作,包括移动它。因此,您也不能对哈希映射执行任何变异操作,从而导致错误。

我可以看到两种安全的方法来解决这个问题:

  • external_2_internal保留自己的字符串副本,即使用HashMap<String, usize>
  • 保持字符串在单独的Vec:
struct IdMapping {
strings: Vec<String>,
external_2_internal: HashMap<usize /* index */, usize>,
internal_2_external: HashMap<usize, usize /* index */>,
}

如果你不想改变结构体的布局,你也可以使用不安全的代码。

相关内容

  • 没有找到相关文章

最新更新