Как исправить `закрытие требует уникального доступа к `*self`, но оно уже заимствовано`?

Я вижу ошибку для этого кода:

error[E0500]: closure requires unique access to `*self` but it is already borrowed
  --> chat/src/user.rs:47:23
   |
   |           return self
   |  ________________-
   | |             .token_to_user_id
   | |_____________________________- borrow occurs here
   |               .get_mut(token)
   |               .and_then(|id| self.find_by_id_mut(id));
   |                -------- ^^^^ ---- second borrow occurs due to use of `*self` in closure
   |                |        |
   |                |        closure construction occurs here
   |                first borrow later used by call

Я понимаю, о чем говорит ошибка, и что мой код нарушает правила заимствования, поскольку он имеет два изменяемых заимствования, однако я не понимаю, как следует писать код на Rust для обработки методов в структурах данных, которые сначала что-то читают, а затем мутировать его. Как решить такие ситуации?

use std::collections::HashMap;

#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, Debug)]
pub struct UserId(pub u32);

#[derive(Default)]
pub struct UserIndex {
    admin: User,
    id_to_user: HashMap<UserId, User>,
    name_to_user_id: HashMap<String, UserId>,
    token_to_user_id: HashMap<String, UserId>,
}

impl UserIndex {
    pub fn insert_user(&mut self, user: User) {
        let id = user.id;
        self.id_to_user.insert(id, user.clone());
        self.token_to_user_id.insert(user.token.clone(), id);
        match user.user_name {
            None => {
                self.admin = user;
            }
            Some(name) => {
                self.name_to_user_id.insert(name, id);
            }
        }
    }

    pub fn ban_user(&mut self, id: UserId) -> bool {
        if let Some(user) = self.find_by_id_mut(&id) {
            user.is_banned = true;
            return true;
        }
        return false;
    }

    fn find_by_id_mut(&mut self, id: &UserId) -> Option<&mut User> {
        return self.id_to_user.get_mut(id);
    }

    fn find_by_token_mut(&mut self, token: &String) -> Option<&mut User> {
        return self
            .token_to_user_id
            .get_mut(token)
            .and_then(|id| self.find_by_id_mut(id));
    }
}

#[derive(Default, Clone)]
pub struct User {
    pub id: UserId,
    // admin doesn't have name and password
    pub user_name: Option<String>,
    pub password: Option<String>,
    pub token: String,
    pub is_banned: bool,
}
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете ссылаться на UserId в UserIndex, когда пытаетесь получить изменяемый доступ к индексу, к счастью, UserId есть Copy, и вы можете просто скопировать его:

    fn find_by_token_mut(&mut self, token: &String) -> Option<&mut User> {
        self
            .token_to_user_id
            .get(token)
            .copied()
            .and_then(|id| self.find_by_id_mut(&id))
    }

(You also didn't need get_mut here)

Спасибо, если бы это был какой-то тяжелый тип, где только одно поле является ссылкой на другую карту, мне также нужно было бы скопировать результат чтения?

litus 11.04.2024 09:55

Не обязательно, я бы, вероятно, использовал Rc/Arc, чтобы избежать копирования дорогостоящей структуры, или, возможно, использовал бы usize с Vec или что-то в этом роде, все зависит от точных деталей. Вы определенно не можете использовать ссылку.

cafce25 11.04.2024 09:56

Другие вопросы по теме