作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 HashMap
,但在如何“释放” HashMap
的可变借项时遇到了绊脚石,却找不到如何执行此操作的良好解释。
这仅是示例,其目的不是“解决问题”,而是了解如何完成此任务和/或为什么不应该这样做。
该示例由一个HashMap
组成,其中存储了一些简单的Record
:
type Map = HashMap<String, Record>;
pub struct Record {
pub count: u32,
pub name: String,
}
impl Record {
fn new<S: Into<String>>(name: S) -> Record {
Record { name: name.into(), count: 0 }
}
pub fn add<'a>(&'a mut self, inc: u32) -> &'a mut Record {
self.count += inc;
self
}
}
add
函数在记录中具有可变函数,但这里并不是真正的罪魁祸首。
Record
中对
HashMap
的引用,以便我们可以就地对其进行修改。除此之外,我们希望能够控制返回的引用,以便我们可以做一些副作用(对于本示例,假设我们要打印出正在发生的事情就足够了,但是可能处理统计数据和/或访问其他存储或进行延迟评估的其他操作)。为了解决这个问题,我们引入了
Handle
结构,该结构保留对
Record
的引用以及对记录来自的
HashMap
的引用。
pub struct Handle<'a> {
map: &'a Map,
record: &'a Record,
}
impl<'a> Handle<'a> {
fn new(record: &'a Record, map: &'a Map) -> Handle<'a> {
println!("Retrieving record");
Handle { record: record, map: map }
}
fn mut_record(&mut self) -> &mut Record {
println!("Modifying record");
self.record
}
}
HashMap
的不可变借用就可以了,因此不应该对
HashMap
进行任何修改。
Handle
只是临时的,我们希望可以大致使用它:
let mut map = HashMap::new();
let foo = get_or_insert(&mut map, "foo");
foo.mut_record().do_something(|record| record.add(3))
get_or_insert
的第一个实现是这样的:
pub fn get_or_insert<'a, S>(map: &'a mut Map, name: S) -> Handle<'a>
where S: Into<String>
{
let key = name.into();
let record = map.entry(key.clone()).or_insert(Record::new(key));
Handle::new(record, map)
}
error[E0502]: cannot borrow `*map` as immutable because it is also borrowed as mutable
--> hashmap.rs:65:29
|
64 | let record = map.entry(key.clone()).or_insert(Record::new(key));
| --- mutable borrow occurs here
65 | Handle::new(record, map)
| ^^^ immutable borrow occurs here
66 | }
| - mutable borrow ends here
HashMap
有两个引用,第一个是可变借项。我们需要“释放” map 的第一个可变借位,然后才能获取不变的借位。我试图以这种方式编写代码,并在第一个可变借位周围添加了一个作用域,期望当作用域结束时它会被“释放”:
pub fn get_or_insert<'a, S>(map: &'a mut Map, name: S) -> Handle<'a>
where S: Into<String>
{
let key = name.into();
let record = {
map.entry(key.clone()).or_insert(Record::new(key))
};
Handle::new(record, map)
}
Handle
,以便
Handle
的生存期不超过
HashMap
的生存期,并在编译时捕获它?我正在寻找一种创建
Handle
的好方法,
Handle
作为实现提供的抽象,抽象出对底层存储的访问。 RefCell
和Rc
丧失资格。 RefCell
,但这将检查从编译时移到了运行时,并且能够在编译时捕获
Handle
的滥用将是有益的。
UnsafeCell
,它可以解决检查而不是解决问题。
最佳答案
在这行上:
let record = map.entry(key.clone()).or_insert(Record::new(key));
record
的类型为
&'a mut Record
,因为
or_insert
返回对存储在
HashMap
中的值的可变引用。这样可以保持对
map
的借用处于 Activity 状态;这就是为什么您得到错误。
get
查找值,以获得不可变的借位。
pub fn get_or_insert<'a, S>(map: &'a mut Map, name: S) -> Handle<'a>
where S: Into<String>
{
let key = name.into();
map.entry(key.clone()).or_insert(Record::new(key.clone()));
let record = map.get(&key).unwrap();
Handle::new(record, map)
}
Handle::mut_record
;
Handle
仅具有对 map 和记录的不变引用,并且您不能使用这些引用获得对记录的可变引用。
关于hashmap - 对包含引用的临时值强制执行生存期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43649480/
我正在使用身份服务器 3 保护 Web 应用程序。我的应用程序分为 2 个 oidc 客户端,一个 ASP.Net MVC 客户端和一个使用 oidc-client javascript 库的 jav
我正在使用 Silex 构建一个小型后台项目,我正在使用 PdoSessionHandler 将 session 存储在数据库中。我已经成功地将 session 存储在数据库中,但似乎将 cookie
我是一名优秀的程序员,十分优秀!