编译器阻止你借用是正确的HashMap
两次。假设在handle_user_data()
你也尝试过借self.users
。你会违反 Rust 中的借用规则,因为你已经有了一个可变的借用,而且你只能拥有一个。
既然借不到self
两次为你handle_user_data()
,我会提出一个解决方案。我不知道它是否是最好的,但它的工作原理没有不安全且没有开销(我认为)。
这个想法是使用一个中间结构来借用其他字段self
:
impl UserHandler {
fn handle_data(&mut self, user_id: i32, data: &str) {
if let Some(user) = self.users.get_mut(&user_id) {
Middle::new(&mut self.counter).handle_user_data(user, data);
}
}
}
struct Middle<'a> {
counter: &'a mut i32,
}
impl<'a> Middle<'a> {
fn new(counter: &'a mut i32) -> Self {
Self {
counter
}
}
fn handle_user_data(&mut self, user: &mut User, data: &str) {
user.send("Message received!");
*self.counter += 1;
}
}
这样,编译器就知道我们不能借用users
twice.
如果您只有一两个东西可以借用,一个快速的解决方案是使用一个将它们作为参数的关联函数:
impl UserHandler {
fn handle_user_data(user: &mut User, data: &str, counter: &mut i32) {
// ...
}
}
我们可以改进这个设计:
struct UserHandler {
users: HashMap<i32, User>, // Maps user id to User objects.
middle: Middle, // Represents internal state
}
impl UserHandler {
fn handle_data(&mut self, user_id: i32, data: &str) {
if let Some(user) = self.users.get_mut(&user_id) {
self.middle.handle_user_data(user, data);
}
}
}
struct Middle {
counter: i32,
}
impl Middle {
fn new(counter: i32) -> Self {
Self {
counter
}
}
fn handle_user_data(&mut self, user: &mut User, data: &str) {
user.send("Message received!");
self.counter += 1;
}
}
现在我们确信我们没有开销并且语法更加清晰。
更多信息请参阅 Niko Matsakis 的博客文章NLL 之后:过程间冲突 http://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/。将此答案映射到博客文章:
- 解决方案#1 ->“将结构视为一般但极端的解决方案”部分
- 解决方案#2 ->“自由变量作为一般但极端的解决方案”部分(此处表示为关联函数)
- 解决方案#3 ->“分解为可能的修复”部分