我的网络应用程序的体系结构可以简化为:
use std::collections::HashMap;
/// Represents remote user. Usually has fields,
/// but we omit them for the sake of example.
struct User;
impl User {
/// Send data to remote user.
fn send(&mut self, data: &str) {
println!("Sending data to user: \"{}\"", data);
}
}
/// A service that handles user data.
/// Usually has non-trivial internal state, but we omit it here.
struct UserHandler {
users: HashMap<i32, User>, // Maps user id to User objects.
counter: i32 // 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) {
user.send("Message received!");
self.counter += 1;
}
}
}
fn main() {
// Initialize UserHandler:
let mut users = HashMap::new();
users.insert(1, User{});
let mut handler = UserHandler{users, counter: 0};
// Pretend we got message from network:
let user_id = 1;
let user_message = "Hello, world!";
handler.handle_data(user_id, &user_message);
}
Playground
这行得通。我想在
UserHandler
中使用一个单独的方法来处理用户输入,当我们已经确定给定ID的用户存在时。所以它变成:impl UserHandler {
fn handle_data(&mut self, user_id: i32, data: &str) {
if let Some(user) = self.users.get_mut(&user_id) {
self.handle_user_data(user, data);
}
}
fn handle_user_data(&mut self, user: &mut User, data: &str) {
user.send("Message received!");
self.counter += 1;
}
}
Playground
突然,它不编译了!
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:24:13
|
23 | if let Some(user) = self.users.get_mut(&user_id) {
| ---------- first mutable borrow occurs here
24 | self.handle_user_data(user, data);
| ^^^^ ---- first borrow later used here
| |
| second mutable borrow occurs here
乍一看,错误很明显:不能有对
self
的可变引用和对self
的属性的可变引用-这就像有两个对self
的可变引用一样。但是,见鬼,我在原始代码中有两个这样的可变引用!为什么这个简单的重构会触发借阅检查器错误?
我该如何处理它并像这样分解
UserHandler::handle_data
方法?如果您想知道我为什么要进行这样的重构,请考虑这样一种情况:当用户可以发送多种类型的消息时,所有这些消息都需要以不同的方式处理,但有一个共同的部分:必须知道哪个
User
对象发送了此消息。 最佳答案
编译器阻止您借用HashMap
两次是正确的。假设在handle_user_data()
中,您还试图借用self.users
。你会打破在铁锈中借钱的规则,因为你已经有一个可变的借钱,你只能有一个。
既然你不能借两次,我就提出一个解决办法。我不知道它是否是最好的,但它的工作没有不安全和开销(我想)。
其思想是使用一个中间结构,它将借用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;
}
}
这样,编译器就知道我们不能借
handle_user_data()
两次。如果您只有一两件东西要借用,一个快速的解决方案是有一个关联函数将它们作为参数:
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;
}
}
现在我们确信我们没有开销,而且语法更清晰。
关于rust - 为什么通过提取方法进行重构会触发借用检查器错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57357506/