【问题标题】:How to resolve the problem when borrowing more than one time in Rust?在 Rust 中多次借用时如何解决问题?
【发布时间】:2022-09-23 12:52:37
【问题描述】:

我有一个结构,其中包含一个用于通信的 TcpStream 和一个用于接收数据的 BytesMut。 当我需要使用它来接收数据时,我打算做以下事情。

#[tokio::test]
async fn test_refmut1() {
    struct Ctx {
        tcps: TcpStream,
        data: BytesMut,
    }
    async fn recv(ctx: Arc<Mutex<Ctx>>) {
        let mut ctx = ctx.lock().await;
        ctx.tcps.read_buf(&mut ctx.data).await.unwrap();
    }
}

显然这样是编译不过去的,因为tcps借了一次,又借了BytesMut,也就是read_buf()参数。

像往常一样,我使用RefCell 包裹另一部分以获得内部可变性。

#[tokio::test]
async fn test_refmut2() {
    struct Ctx {
        tcps: TcpStream,
        data: RefCell<BytesMut>,
    }
    
    async fn recv(ctx: Arc<Mutex<Ctx>>) {
        let mut ctx = ctx.lock().await;
        let tcps = &ctx.tcps;
        let mut data = ctx.data.borrow_mut();
        ctx.tcps.read_buf(&data).await.unwrap();
    }
}

但是,这仍然无法编译,因为read_buf() 需要&amp;mut BytesMut 类型的参数,我现在通过RefCell 借用它作为RefMut&lt;BytesMut&gt; 类型的参数。

但我知道这两者不能直接兑换,我该怎么办?

  • 第一个例子中的ctx.tcpsctx.data 应该是不相交的借用。为什么不编译?

标签: rust mutex borrow-checker


【解决方案1】:

lock() 方法不提供引用,而是提供MutexGuard。 多次使用此防护时,我们借用它的次数相同,这可能会引入您报告的问题。 一种解决方案是仅获取此守卫持有的参考一次&amp;mut * 技巧,实际上是.deref_mut()),然后多次使用此引用,依赖于其他答案中所述的拆分借用。

async fn test_refmut1() {
    struct Ctx {
        tcps: TcpStream,
        data: BytesMut,
    }
    async fn recv(ctx: Arc<Mutex<Ctx>>) {
        let mut ctx_guard = ctx.lock().await;
        let ctx = &mut *ctx_guard;
        ctx.tcps.read_buf(&mut ctx.data).await.unwrap();
    }
}

【讨论】:

  • 这是一个非常有趣的方法!我得玩一下,谢谢。
【解决方案2】:

显然这样是编译不出来的,因为tcps借了一次,又借了read_buf()参数的BytesMut。

这不是问题吗? Rust 可以拆分借用,但有时您必须稍微调整一下(可能取决于您使用的版本)。 I whipped up a quick variant and it compiles fine:

use std::io::*;

struct Ctx {
    tcps: Stdin,
    data: Vec<u8>,
}

fn recv(mut ctx: Ctx) {
    ctx.tcps.read_to_end(&mut ctx.data).unwrap();
}

fn main() {
    let ctx = Ctx { tcps: stdin(), data: Vec::new() };
    recv(ctx);
}

【讨论】:

    【解决方案3】:

    你可以拆分借用Ctx,一个干净的方法是给destructure一个&amp;mut的上下文版本:

    #[tokio::test]
    async fn test_refmut1() {
        struct Ctx {
            tcps: TcpStream,
            data: BytesMut,
        }
        impl Ctx {
            async fn read(&mut self) {
                let Self { tcps, data } = self;
                tcps.read(data).await.unwrap();
            }
        }
        async fn recv(ctx: Arc<Mutex<Ctx>>) {
            let mut ctx = ctx.lock().await;
            ctx.read();
        }
    }
    

    Playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 2013-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-05
      相关资源
      最近更新 更多