不能从 hashmap 中借用可变的值,因为它也被借用为不可变的
Cannot borrow value from a hashmap as mutable because it is also borrowed as immutable
我想同时从一个hashmap中获取两个值,但我无法避免出现以下错误,我将代码简化如下,谁能帮我解决这个错误。
#[warn(unused_variables)]
use hashbrown::HashMap;
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn do_expensive_cal(i: usize) -> Vec<usize> {
vec![i,i,i]
}
fn main() {
let size = 1000000;
let mut hash: HashMap<usize, Vec<usize>> = HashMap::new();
for i in 0..size{
if i > 0 {
hash.remove(&(i - 1));
}
if !hash.contains_key(&i){
hash.insert(i, do_expensive_cal(i));
}
let data1 = hash.get(&i).unwrap();
for j in i + 1..size {
if do_check(i, j) {
break
}
if !hash.contains_key(&j){
hash.insert(j, do_expensive_cal(j));
}
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}
错误[E0502]:无法借用 hash
作为可变的,因为它也被借用为不可变的
--> src/main.rs:26:8
|
19 | let data1 = hash.get(&i).unwrap();
| ------------ immutable borrow occurs here
...
26 | hash.insert(j, vec![1,2,3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
29 | let res = do_cal(data1, data2);
| ----- immutable borrow later used here
有关此错误的更多信息,请尝试 rustc --explain E0502
。
错误:由于先前的错误
,无法编译 playground
考虑一下:借用检查器不知道 hash.insert(j, …)
会单独保留您使用 hash.insert(i, …)
插入的数据。对于借用检查器,hash.insert(…)
可以对 hash
中的任何元素执行任何操作,包括重写或删除它。所以你不能在 hash.insert(j, …)
.
上保留引用 data1
如何克服?最简单的可能就是移动 let data1 = hash.get(…)
这样它就不用活那么久了:
let data1 = hash.get(&i).unwrap();
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
这当然会在每个循环迭代中查找 data1
(而且它必须,因为 hash.insert(j, …)
可能已经调整大小并因此重新分配 hashmap 的内容,给 data1
一个新的hashmap 中的存储位置)。为了完整起见,有一些方法可以解决这个问题,但我不建议您这样做:
- 克隆:
let data1 = hash.get(&i).unwrap().clone()
(如果你的 vecs 很短,这实际上可能是合理的......)
- 作为一种降低克隆成本的方法,您可以改用
HashMap<usize, Rc<Vec<usize>>>
(您只需要克隆 Rc
,而不是整个 Vec
)
- 如果您需要对
do_call
的两个参数进行可变引用,您可以将 Rc
与 RefCell
结合使用:Rc<RefCell<Vec<…>>>
- 如果您需要对其进行更多的过度设计,您可以将
Rc
替换为从 bump 分配器中分配获得的引用,例如bumpalo.
由于散列 table 的键是整数 0..100,您可以使用 Vec
来执行这些步骤,暂时将 Vec
分成 2 片以允许一侧的突变。如果你需要一个 HashMap
用于以后的计算,你可以从 Vec
.
创建一个 HashMap
以下代码可以编译但会出现错误,因为 j - 10
计算下溢:
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn main() {
let size = 100;
let mut v: Vec<Option<Vec<usize>>> = vec![None; size];
for i in 0..size {
let (v1, v2) = v.split_at_mut(i + 1);
if v1[i].is_none() {
v1[i] = Some(vec![1,2,3]);
}
let data1 = v1[i].as_ref().unwrap();
for (j, item) in (i + 1..).zip(v2.iter_mut()) {
if do_check(i, j) {
break
}
if item.is_none() {
*item = Some(vec![1,2,3]);
}
let data2 = item.as_ref().unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}
我想同时从一个hashmap中获取两个值,但我无法避免出现以下错误,我将代码简化如下,谁能帮我解决这个错误。
#[warn(unused_variables)]
use hashbrown::HashMap;
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn do_expensive_cal(i: usize) -> Vec<usize> {
vec![i,i,i]
}
fn main() {
let size = 1000000;
let mut hash: HashMap<usize, Vec<usize>> = HashMap::new();
for i in 0..size{
if i > 0 {
hash.remove(&(i - 1));
}
if !hash.contains_key(&i){
hash.insert(i, do_expensive_cal(i));
}
let data1 = hash.get(&i).unwrap();
for j in i + 1..size {
if do_check(i, j) {
break
}
if !hash.contains_key(&j){
hash.insert(j, do_expensive_cal(j));
}
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}
错误[E0502]:无法借用 hash
作为可变的,因为它也被借用为不可变的
--> src/main.rs:26:8
|
19 | let data1 = hash.get(&i).unwrap();
| ------------ immutable borrow occurs here
...
26 | hash.insert(j, vec![1,2,3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
29 | let res = do_cal(data1, data2);
| ----- immutable borrow later used here
有关此错误的更多信息,请尝试 rustc --explain E0502
。
错误:由于先前的错误
playground
考虑一下:借用检查器不知道 hash.insert(j, …)
会单独保留您使用 hash.insert(i, …)
插入的数据。对于借用检查器,hash.insert(…)
可以对 hash
中的任何元素执行任何操作,包括重写或删除它。所以你不能在 hash.insert(j, …)
.
data1
如何克服?最简单的可能就是移动 let data1 = hash.get(…)
这样它就不用活那么久了:
let data1 = hash.get(&i).unwrap();
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
这当然会在每个循环迭代中查找 data1
(而且它必须,因为 hash.insert(j, …)
可能已经调整大小并因此重新分配 hashmap 的内容,给 data1
一个新的hashmap 中的存储位置)。为了完整起见,有一些方法可以解决这个问题,但我不建议您这样做:
- 克隆:
let data1 = hash.get(&i).unwrap().clone()
(如果你的 vecs 很短,这实际上可能是合理的......) - 作为一种降低克隆成本的方法,您可以改用
HashMap<usize, Rc<Vec<usize>>>
(您只需要克隆Rc
,而不是整个Vec
) - 如果您需要对
do_call
的两个参数进行可变引用,您可以将Rc
与RefCell
结合使用:Rc<RefCell<Vec<…>>>
- 如果您需要对其进行更多的过度设计,您可以将
Rc
替换为从 bump 分配器中分配获得的引用,例如bumpalo.
由于散列 table 的键是整数 0..100,您可以使用 Vec
来执行这些步骤,暂时将 Vec
分成 2 片以允许一侧的突变。如果你需要一个 HashMap
用于以后的计算,你可以从 Vec
.
HashMap
以下代码可以编译但会出现错误,因为 j - 10
计算下溢:
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn main() {
let size = 100;
let mut v: Vec<Option<Vec<usize>>> = vec![None; size];
for i in 0..size {
let (v1, v2) = v.split_at_mut(i + 1);
if v1[i].is_none() {
v1[i] = Some(vec![1,2,3]);
}
let data1 = v1[i].as_ref().unwrap();
for (j, item) in (i + 1..).zip(v2.iter_mut()) {
if do_check(i, j) {
break
}
if item.is_none() {
*item = Some(vec![1,2,3]);
}
let data2 = item.as_ref().unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}