如何避免结构方法中的双重借用错误

How to avoid a double borrow error in struct method

我是 Rust 的新手,我正在尝试找出如何修复下面代码段中的 Trader.gateway_client 方法。它是由可变的双重借用引起的。修复代码的正确方法是什么(之前没有克隆 self.gateway 字符串)。

use std::collections::{HashMap};


pub struct GatewayClient {
    gateway: String,
    strategy: String,
}


pub struct Trader {
    gateway_clients: HashMap<String, GatewayClient>,
    strategy: String,
}


impl GatewayClient {
    pub fn new(gateway: &str, strategy: &str) -> Self {
        GatewayClient {
            gateway: String::from(gateway),
            strategy: String::from(strategy),
        }
    }
}


impl Trader {
    pub fn new(strategy: &str) -> Self {
        Trader {
            gateway_clients: HashMap::default(),
            strategy: String::from(strategy),
        }
    }

    pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
        self.gateway_clients.entry(String::from(gateway)).or_insert_with(|| {
            GatewayClient::new(gateway, &self.strategy)
        })
    }
}

编译器抛出的错误是

63 |       pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
   |                             - let's call the lifetime of this reference `'1`
64 |           self.gateway_clients.entry(String::from(gateway)).or_insert_with(|| {
   |           --------------------                                             ^^ immutable borrow occurs here
   |           |
   |  _________mutable borrow occurs here
   | |
65 | |             GatewayClient::new(gateway, &self.strategy)
   | |                                          ------------- second borrow occurs due to use of `self` in closure
66 | |         })
   | |__________- returning this value requires that `self.gateway_clients` is borrowed for `'1`

您只是不需要使用允许通过闭包执行自定义代码的 .or_insert_with。您只想插入一个值,并且有一个方法 .or_insert 接受一个值。

pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
    self.gateway_clients
        .entry(gateway.to_string())
        .or_insert(GatewayClient::new(gateway, &self.strategy))
}

此外,如果您想要摆脱使用 String::from(...) 创建的一百万个新字符串,您可以查看 std::borrow::Cow 类型

解决借用冲突的一种方法是通过从 self 外部提取您需要的内容来消除回调中的第二个显式借用。

    pub fn gateway_client(&mut self, gateway: &str) -> &mut GatewayClient {
        let strategy = &self.strategy;

        self.gateway_clients
            .entry(gateway.into())
            .or_insert_with(|| GatewayClient::new(gateway, strategy))
    }

这看起来可能是回调中对 self 的第二次借用,但编译器接受了这一点。

.or_insert_with() 对比 .or_insert()

建议使用 .or_insert() 进行修复,但您选择使用 .or_insert_with() 是正确的。

在这种情况下,使用 .or_insert_with() 优于 .or_insert() 的优点是只有在条目不存在时才会执行回调。如果使用.or_insert(),无论条目是否存在,每次都会调用GatewayClient::new()