引用删除后哈希映射多个可变借用问题
Hashmap multiple mutable borrow issue after reference drop
我试图传递一个 HashMap,它通过一组嵌套 enums/structs 存储值。迭代过程中出现多重可变性问题,甚至所有引用应该被删除。
总体思路是拥有一个值向量,遍历它们并简化它们,在 HashMap 中跟踪它们。有两个简化阶段。
一般流程类似于
run(Vec<ComplexVal>)
-for each val->
val.fix_complex(holder)
-for each `smp` SimpleVal in val->
basicval = Simplifier::step(smp, holder)
holder.insert("name", basicval)
但问题是 holder
在每个阶段都是可变借用的,并且没有 supposed 是 ComplexVal
的任何引用到 holder
并且由于 borrowchecker 不喜欢多次借用,它失败了。
完整的游乐场片段:here
它发生在这个片段中:
pub fn run(&mut self, mut vals: Vec<ComplexVal>) {
let mut holder = Holder{hold:HashMap::new()};
// .. setup holder code omitted
let len = vals.len();
for _ in 0..len {
let mut val = vals.remove(0); // remove from vec, should drop after running
println!("Running {:?}", val);
match val {
ComplexVal::Cmplx1(mut c) => {
c.fix_complex(&mut holder)
},
//... more cases of different types of values omitted for simplicity
}
// val *should* be dropped here, and therefore the mutable borrow of holder?
}
println!("Holder: {:?}", holder);
}
}
我唯一能想到的是它在某种程度上与创建时的BasicVal::Ref(&BasicVal)
值有关。
我需要 return 类型 &BasicVal
的引用,所以我不能使用常规 fn() -> &BasicVal
因为引用会悬空,所以我传递了 ret
值被修改并用作 return 值的存储。
我也曾尝试 return 枚举 BasicVal::Ref(&BasicVal)
,但 运行 遇到了相同的可变性问题。
下面的例子是一个更简单的版本,它(在某种程度上)展示了同样的错误,只是想我会包括这个上下文,以防有人对如何实现这个有另一个想法而不会出现这些问题
代码(已编辑)
编辑:我犯了一个错误,不需要 holder
和 ret
的生命周期明确地相同,所以我为它做了一个更新的例子
use std::borrow::BorrowMut;
///////////////////////////////
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
#[derive(Debug)]
enum BasicVal<'a> {
Ref(&'a BasicVal<'a>),
Val1(BasicStruct),
}
#[derive(Debug)]
struct Holder<'b> {
hold: HashMap<String, RefCell<BasicVal<'b>>>,
}
#[derive(Debug)]
struct BasicStruct {
val: i32,
}
impl<'a> BasicVal<'a> {
pub fn empty() -> Self { BasicVal::Val1(BasicStruct { val: 0 }) }
}
// must match sig of modify_val_ref
fn modify_val<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
*ret = BasicVal::Val1(BasicStruct { val: 5 });
}
// must match sig of modify_val
fn modify_val_ref<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
ret = holder.hold.get("reference_val").unwrap().borrow_mut();
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
let mut v = RefCell::new(BasicVal::empty());
println!("Original {:?}", v);
modify_val(holder, v.borrow_mut());
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", holder.hold.get("Data"));
}
pub fn test_dropborrow() {
let mut holder = Holder { hold: HashMap::new() };
holder.hold.insert(
"reference_val".to_string(),
RefCell::new(BasicVal::Val1(BasicStruct { val: 8 })),
);
do_modify(&mut holder);
}
pub fn main() {
test_dropborrow();
}
编辑:仅使用 holder 作为临时 return 值给我带来了多重可变借用问题,因此该解决方法不起作用。我也用同样问题的 RefCell 尝试过。
fn modify_val<'f>(holder: &'f mut Holder<'f>) {
holder.hold.insert("$return".to_string(), BasicVal::Val1(BasicStruct{val: 5}));
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
modify_val(holder);
let mut v = holder.hold.remove("$return").unwrap();
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", v);
}
错误:
935 | fn do_modify<'f>(holder: &'f mut Holder<'f>) {
| -- lifetime `'f` defined here
936 |
937 | modify_val(holder);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*holder` is borrowed for `'f`
938 | let mut v = holder.hold.remove("$return").unwrap();
| ^^^^^^^^^^^ second mutable borrow occurs here
非常感谢任何帮助!!!
弄清楚了,本质上 BasicVal<'a>
导致 Holder
在循环的连续迭代中可变地借用自身,因此删除生命周期几乎是唯一的解决方案
我试图传递一个 HashMap,它通过一组嵌套 enums/structs 存储值。迭代过程中出现多重可变性问题,甚至所有引用应该被删除。
总体思路是拥有一个值向量,遍历它们并简化它们,在 HashMap 中跟踪它们。有两个简化阶段。
一般流程类似于
run(Vec<ComplexVal>)
-for each val->
val.fix_complex(holder)
-for each `smp` SimpleVal in val->
basicval = Simplifier::step(smp, holder)
holder.insert("name", basicval)
但问题是 holder
在每个阶段都是可变借用的,并且没有 supposed 是 ComplexVal
的任何引用到 holder
并且由于 borrowchecker 不喜欢多次借用,它失败了。
完整的游乐场片段:here
它发生在这个片段中:
pub fn run(&mut self, mut vals: Vec<ComplexVal>) {
let mut holder = Holder{hold:HashMap::new()};
// .. setup holder code omitted
let len = vals.len();
for _ in 0..len {
let mut val = vals.remove(0); // remove from vec, should drop after running
println!("Running {:?}", val);
match val {
ComplexVal::Cmplx1(mut c) => {
c.fix_complex(&mut holder)
},
//... more cases of different types of values omitted for simplicity
}
// val *should* be dropped here, and therefore the mutable borrow of holder?
}
println!("Holder: {:?}", holder);
}
}
我唯一能想到的是它在某种程度上与创建时的BasicVal::Ref(&BasicVal)
值有关。
我需要 return 类型 &BasicVal
的引用,所以我不能使用常规 fn() -> &BasicVal
因为引用会悬空,所以我传递了 ret
值被修改并用作 return 值的存储。
我也曾尝试 return 枚举 BasicVal::Ref(&BasicVal)
,但 运行 遇到了相同的可变性问题。
下面的例子是一个更简单的版本,它(在某种程度上)展示了同样的错误,只是想我会包括这个上下文,以防有人对如何实现这个有另一个想法而不会出现这些问题
代码(已编辑)
编辑:我犯了一个错误,不需要 holder
和 ret
的生命周期明确地相同,所以我为它做了一个更新的例子
use std::borrow::BorrowMut;
///////////////////////////////
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
#[derive(Debug)]
enum BasicVal<'a> {
Ref(&'a BasicVal<'a>),
Val1(BasicStruct),
}
#[derive(Debug)]
struct Holder<'b> {
hold: HashMap<String, RefCell<BasicVal<'b>>>,
}
#[derive(Debug)]
struct BasicStruct {
val: i32,
}
impl<'a> BasicVal<'a> {
pub fn empty() -> Self { BasicVal::Val1(BasicStruct { val: 0 }) }
}
// must match sig of modify_val_ref
fn modify_val<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
*ret = BasicVal::Val1(BasicStruct { val: 5 });
}
// must match sig of modify_val
fn modify_val_ref<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
ret = holder.hold.get("reference_val").unwrap().borrow_mut();
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
let mut v = RefCell::new(BasicVal::empty());
println!("Original {:?}", v);
modify_val(holder, v.borrow_mut());
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", holder.hold.get("Data"));
}
pub fn test_dropborrow() {
let mut holder = Holder { hold: HashMap::new() };
holder.hold.insert(
"reference_val".to_string(),
RefCell::new(BasicVal::Val1(BasicStruct { val: 8 })),
);
do_modify(&mut holder);
}
pub fn main() {
test_dropborrow();
}
编辑:仅使用 holder 作为临时 return 值给我带来了多重可变借用问题,因此该解决方法不起作用。我也用同样问题的 RefCell 尝试过。
fn modify_val<'f>(holder: &'f mut Holder<'f>) {
holder.hold.insert("$return".to_string(), BasicVal::Val1(BasicStruct{val: 5}));
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
modify_val(holder);
let mut v = holder.hold.remove("$return").unwrap();
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", v);
}
错误:
935 | fn do_modify<'f>(holder: &'f mut Holder<'f>) {
| -- lifetime `'f` defined here
936 |
937 | modify_val(holder);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*holder` is borrowed for `'f`
938 | let mut v = holder.hold.remove("$return").unwrap();
| ^^^^^^^^^^^ second mutable borrow occurs here
非常感谢任何帮助!!!
弄清楚了,本质上 BasicVal<'a>
导致 Holder
在循环的连续迭代中可变地借用自身,因此删除生命周期几乎是唯一的解决方案