rust - 有没有办法使用地图中元素的值来更新另一个没有内部可变性的元素?
问题描述
BTreeMap
我正在尝试从来自同一映射的元素(A)中查找元素(B)的值,然后将 A 的值与 B 的值进行变异。
我知道我可以使用 aRefCell
来避免“不能将 X 作为不可变借用,因为 X 也作为可变借用”错误,但我想知道是否有更惯用、更安全的方法来做到这一点。
我曾想过尝试存储指向其他元素的指针,但这不起作用,因为元素的内存位置会随着向 中添加元素而移动BTreeMap
,因此这是不安全和错误的。
这种模式有更好的方法吗?
初步尝试
use std::collections::BTreeMap;
struct Map(BTreeMap<String, Foo>);
impl Map {
fn new() -> Self {
Map(BTreeMap::new())
}
fn calc_node(&mut self, name: &str) {
self.0.get_mut(name).unwrap().calc_value(self)
}
}
struct Foo {
name: String,
v: i32,
lookup: String,
}
impl Foo {
fn new(name: String, value: i32, lookup: String) -> Self {
Self {
name,
v: value,
lookup,
}
}
fn calc_value(&mut self, map: &Map) {
self.v = map.0.get(&self.lookup).unwrap().v * 2 // really what I'm trying to do
}
}
fn main() {
let mut map = Map::new();
map.0.insert(
"a".to_string(),
Foo::new("a".to_string(), 1, "b".to_string()),
);
map.0.insert(
"b".to_string(),
Foo::new("b".to_string(), 2, "a".to_string()),
);
println!("{:?}", map.0.get("a").unwrap().v);
map.calc_node("a");
println!("{:?}", map.0.get("a").unwrap().v);
}
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/main.rs:11:50
|
11 | self.0.get_mut(name).unwrap().calc_value(self)
| ------ ---------- ^^^^ immutable borrow occurs here
| | |
| | mutable borrow later used by call
| mutable borrow occurs here
使用RefCell
use std::cell::RefCell;
use std::collections::BTreeMap;
struct Map(BTreeMap<String, RefCell<Foo>>);
impl Map {
fn new() -> Self {
Map(BTreeMap::new())
}
fn calc_node(&self, name: &str) {
self.0.get(name).unwrap().borrow_mut().calc_value(self)
}
}
struct Foo {
name: String,
v: i32,
lookup: String,
}
impl Foo {
fn new(name: String, value: i32, lookup: String) -> Self {
Self {
name,
v: value,
lookup,
}
}
fn calc_value(&mut self, map: &Map) {
self.v = map.0.get(&self.lookup).unwrap().borrow().v * 2
}
}
fn main() {
let mut map = Map::new();
map.0.insert(
"a".to_string(),
RefCell::new(Foo::new("a".to_string(), 1, "b".to_string())),
);
map.0.insert(
"b".to_string(),
RefCell::new(Foo::new("b".to_string(), 2, "a".to_string())),
);
println!("{:?}", map.0.get("a").unwrap().borrow().v);
map.calc_node("a");
println!("{:?}", map.0.get("a").unwrap().borrow().v);
}
我得到正确的结果:
1
4
RefCell
s 有运行时成本,理想情况下,我希望能够尽快访问引用的元素。
解决方案
推荐阅读
- sql - 获取连续 30 天登录网站的用户数
- c# - 在 .net POST 请求中使用 Axis2 Web 服务的问题返回空
- javascript - Javascript - 将数组列表的对象转换为另一种格式?
- python-3.x - 在python中访问嵌套列表中的元素
- elasticsearch - 无法添加片段编号的高亮选项
- java - 从 JAVA 中的 HTTP 流连接读取出站消息
- python - 将 HTML 嵌套列表拆分为 python 列表
- facebook - Facebook messenger android 人选菜单红圈带 1
- android - 带有复选框的android DialogFragment不起作用
- python - 我如何解释 Keras predict_generator 的结果?