代码之家  ›  专栏  ›  技术社区  ›  James Taylor

Future不是Send,仅当来自异步Trait时

  •  0
  • James Taylor  · 技术社区  · 2 年前

    我有一个特点 Serializer :

    trait Serializer {
        fn serialize(&self, data: Rc<()>) -> Result<(), Error>;
    }
    

    还有一些 Foo 其实现了它。值得注意的是, data 不是 Send .

    实际实现需要一个异步上下文来执行,所以我将异步运行时的创建与实际实现分开,如下所示:

    struct Foo {}
    
    impl Foo {
        async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
            unimplemented!();
        }
    }
    
    impl Serializer for Foo {
        fn serialize(&self, data: Rc<()>) -> Result<(), Error> {
            let runtime = Builder::new_current_thread().enable_all().build().unwrap();
            runtime.block_on(async move { self.async_serialize(data).await })
        }
    }
    

    这是我所期望的编译和工作方式。

    如果我重构代码,使异步运行时的创建通过一个特性来完成:

    #[async_trait]
    trait AsyncSerializer {
        async fn async_serialize(&self, data: Rc<()>) -> Result<(), Error>;
    }
    
    #[async_trait]
    impl AsyncSerializer for Foo {
        async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
            unimplemented!();
        }
    }
    

    这不编译,现在抱怨 Rc<()> 不是 邮寄 :

    error: future cannot be sent between threads safely
      --> src/main.rs:19:73
       |
    19 |       async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
       |  _________________________________________________________________________^
    20 | |         unimplemented!();
    21 | |     }
       | |_____^ future created by async block is not `Send`
       |
       = help: within `impl Future<Output = Result<(), anyhow::Error>>`, the trait `Send` is not implemented for `Rc<()>`
    note: captured value is not `Send`
    

    这个错误消息对我来说很有意义, Rc 不是 邮寄 但是

    • 为什么以前这不是问题?先前的实现( impl on Foo impl AsyncSerializer for Foo )看起来和我相似。
    • 我能包起来吗 数据 以某种方式避免这种情况?
    1 回复  |  直到 2 年前
        1
  •  6
  •   Ian S.    2 年前

    那样的方式 #[async_trait] 去糖你的代码需要发送你的期货,正如解释的那样 here 。若要修复此问题,请将属性宏更改为 #[async_trait(?Send)] .