You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在生成异步任务时让AsyncWrite具备可移动性?

解决T cannot be unpinned编译错误

问题原因

  1. AsyncWrite方法的Pin约束:AsyncWrite::write要求self必须是Pin<&mut Self>,而MutexGuard<T>只有当T实现Unpin时,才能自动转换为可Pin的引用,否则编译器无法保证T不会被移动,导致约束不满足。
  2. 引用生命周期不匹配:data是&[u8]类型的引用,直接移入tokio::spawn的异步块会触发生命周期错误——under_test中data的生命周期无法覆盖异步任务的整个执行周期。
  3. 未执行异步方法:write是异步方法,仅调用方法只会创建一个Future对象,必须通过.await才能触发执行。

修复方案

1. 给泛型添加Unpin约束

在under_test的泛型参数中补充Unpin,由于测试用的TcpStream本身实现了Unpin,这个约束完全适配场景,能让MutexGuard<T>安全地被Pin。

2. 复制数据获取所有权

将&[u8]转换为Vec<u8>,让数据拥有独立所有权,可安全移入异步任务中,避免生命周期冲突。

3. 正确执行异步方法并处理结果

调用writer.write(&data).await触发异步写入,测试场景中可用.unwrap()简化错误处理。

修改后的完整代码

use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::Mutex;

#[tokio::test]
async fn test_spawn_move_writable() {
    async fn under_test<T: AsyncWrite + Unpin>(writer: Arc<Mutex<T>>, data: &[u8]) {
        let data = data.to_vec(); // 复制数据获取所有权
        tokio::spawn(async move {
            let mut writer = writer.lock().await;
            writer.write(&data).await.unwrap(); // 等待异步写入完成
        })
        .await
        .unwrap();
    }

    let addr = "127.0.0.1:3000";
    let tcps = TcpListener::bind(addr).await.unwrap();
    tokio::spawn(async move {
        loop {
            let (mut client, caddr) = tcps.accept().await.unwrap();
            tokio::spawn(async move {
                let mut buf = vec![0; 16];
                loop {
                    let size = client.read(&mut buf).await.unwrap();
                    println!(
                        "{:?}> {}",
                        caddr,
                        std::str::from_utf8(&buf[0..size]).unwrap()
                    );
                }
            });
        }
    });

    let tcps = TcpStream::connect(addr).await.unwrap();
    let tcps = Arc::new(Mutex::new(tcps));
    for data in [b"hello", b"world", b"rust", b"tokio"] {
        under_test(tcps.clone(), &data[..]).await;
    }
}

额外说明

如果需要支持非Unpin的AsyncWrite实现,可以将Arc<Mutex<T>>改为Arc<Mutex<Pin<Box<T>>>>,通过Box::pin手动固定对象,满足Pin约束。但在当前测试场景下,直接添加Unpin约束是最简洁的方案。

内容的提问来源于stack exchange,提问作者progquester

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:05:26