【问题标题】:Accessing hashmap field value as &mut inside struct impl在 struct impl 中以 &mut 的形式访问 hashmap 字段值
【发布时间】:2015-07-06 05:40:32
【问题描述】:

给定一个像这样的简单结构:

struct Server {
  clients: HashMap<usize, Client>
}

&amp;mut 身份访问Client 的最佳方式是什么?考虑以下代码:

use std::collections::HashMap;

struct Client {
  pub poked: bool
}

impl Client {
  pub fn poked(&self) -> bool {
    self.poked
  }

  pub fn set_poked(&mut self) {
    self.poked = true;
  }
}

struct Server {
  clients: HashMap<usize, Client>
}

impl Server {
  pub fn poke_client(&mut self, token: usize) {
    let client = self.clients.get_mut(&token).unwrap();
    self.poke(client);
  }

  fn poke(&self, c: &mut Client) {
    c.set_poked();
  }
}

fn main() {
    let mut s = Server { clients: HashMap::new() };
    s.clients.insert(1, Client { poked: false });

    s.poke_client(1);

    assert!(s.clients.get(&1).unwrap().poked() == true);
}

我看到的仅有的两个选项是在客户端中使用RefCell/Cell,这让事情看起来非常糟糕:

pub struct Client {
    nickname: RefCell<Option<String>>,
    username: RefCell<Option<String>>,
    realname: RefCell<Option<String>>,
    hostname: RefCell<Option<String>>,
    out_socket: RefCell<Box<Write>>,
}

或者将clients 包裹在RefCell 中,这使得Server 不可能有像这样的简单方法:

pub fn client_by_token(&self, token: usize) -> Option<&Client> {
    self.clients_tok.get(&token)
}

强迫我使用闭包(例如with_client_by_token(|c| ...))。

【问题讨论】:

  • Rust 风格指南是 4 空格缩进。

标签: hashmap rust borrow-checker


【解决方案1】:

正如错误消息所说,当 self 已经可变借用时,您不能再借用它:

<anon>:24:5: 24:9 error: cannot borrow `*self` as immutable because `self.clients` is also borrowed as mutable
<anon>:24     self.poke(client);
              ^~~~

在你的方法中:

pub fn poke_client(&mut self, token: usize) {
    let client = self.clients.get_mut(&token).unwrap();
    self.poke(client);
}

当你调用poke方法时,你在第一行可变地借用self,然后在第二行再次尝试借用它。最简单的解决方案是在这里拨打Client::set_poked

pub fn poke_client(&mut self, token: usize) {
    let client = self.clients.get_mut(&token).unwrap();
    client.set_poked();
}

另一种解决方法是引入不需要self的方法:

impl Server {
    pub fn poke_client(&mut self, token: usize) {
        let client = self.clients.get_mut(&token).unwrap();
        Server::poke(client);
    }

    fn poke(c: &mut Client) {
        c.set_poked();
    }
}

您可以传递selfpoke 所需的任何其他部分。这可能是引入一个介于ServerClient 之间的新对象的好时机。

【讨论】:

    猜你喜欢
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2020-07-19
    • 2017-09-30
    • 2020-10-13
    • 1970-01-01
    相关资源
    最近更新 更多