Cor*_*ker 1 ownership rust borrowing
我可以理解 Rust 中的借用/所有权概念,但我不知道如何解决这种情况:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
Run Code Online (Sandbox Code Playgroud)
编译器有错误:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我get之前执行(读取值)时无法在火柴臂中变异;self.t.get当变异开始时就结束了remove。
Option<&u16>这是由于返回的result () 的范围造成的吗get?确实,结果的生命周期在匹配表达式内有一个范围,但这种设计模式使用得非常频繁(在匹配表达式中进行变异)。
我该如何解决该错误?
函数的声明HashMap::<K,V>::get()有点简单:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
Run Code Online (Sandbox Code Playgroud)
这意味着它返回对所包含值的可选引用,而不是值本身。由于返回的引用指向映射内的值,因此它实际上借用了映射,也就是说,当该引用存在时,您无法更改映射。这个限制是为了保护你,如果你在引用仍然存在的情况下删除这个值会发生什么?
所以当你写:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
Run Code Online (Sandbox Code Playgroud)
捕获r的类型是&u16,其生命周期是self.t,也就是说,它正在借用它。self因此,您无法获得调用remove所需的可变引用。
解决您的问题的最简单的解决方案是clone()解决每个生命周期问题模式。由于您的值的类型为u16,即Copy,它实际上很简单:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Run Code Online (Sandbox Code Playgroud)
Nowr实际上是类型,u16所以它不借用任何东西,你可以self随意变异。
如果您的键/值类型不是,Copy您可以尝试使用clone它们,如果您愿意为此付费的话。如果没有,还有另一个选择,因为您的remove()函数不会修改HashMap但不相关的HashSet. 如果你注意不要重新借用,你仍然可以改变该集合self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
916 次 |
| 最近记录: |