Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Type erasure for async trait methods

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
NotificationsYou must be signed in to change notification settings

dtolnay/async-trait

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

githubcrates.iodocs.rsbuild status

The stabilization of async functions in traits in Rust 1.75 did not includesupport for using traits containing async functions asdyn Trait. Trying touse dyn with an async trait produces the following error:

pubtraitTrait{asyncfnf(&self);}pubfnmake() ->Box<dynTrait>{unimplemented!()}
error[E0038]: the trait `Trait` is not dyn compatible --> src/main.rs:5:22  |5 | pub fn make() -> Box<dyn Trait> {  |                      ^^^^^^^^^ `Trait` is not dyn compatible  |note: for a trait to be dyn compatible it needs to allow building a vtable      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> src/main.rs:2:14  |1 | pub trait Trait {  |           ----- this trait is not dyn compatible...2 |     async fn f(&self);  |              ^ ...because method `f` is `async`  = help: consider moving `f` to another trait

This crate provides an attribute macro to make async fn in traits work with dyntraits.

Please refer towhy async fn in traits are hard for a deeper analysisof how this implementation differs from what the compiler and language delivernatively.


Example

This example implements the core of a highly effective advertising platformusing async fn in a trait.

The only thing to notice here is that we write an#[async_trait] macro on topof traits and trait impls that contain async fn, and then they work. We get tohaveVec<Box<dyn Advertisement + Sync>> or&[&dyn Advertisement], forexample.

use async_trait::async_trait;#[async_trait]traitAdvertisement{asyncfnrun(&self);}structModal;#[async_trait]implAdvertisementforModal{asyncfnrun(&self){self.render_fullscreen().await;for _in0..4u16{remind_user_to_join_mailing_list().await;}self.hide_for_now().await;}}structAutoplayingVideo{media_url:String,}#[async_trait]implAdvertisementforAutoplayingVideo{asyncfnrun(&self){let stream =connect(&self.media_url).await;        stream.play().await;// Video probably persuaded user to join our mailing list!Modal.run().await;}}

Supported features

It is the intention that all features of Rust traits should work nicely with#[async_trait], but the edge cases are numerous.Please file an issue if yousee unexpected borrow checker errors, type errors, or warnings. There is no useofunsafe in the expanded code, so rest assured that if your code compiles itcan't be that badly broken.

  • 👍 Self by value, by reference, by mut reference, or no self;
  • 👍 Any number of arguments, any return value;
  • 👍 Generic type parameters and lifetime parameters;
  • 👍 Associated types;
  • 👍 Having async and non-async functions in the same trait;
  • 👍 Default implementations provided by the trait;
  • 👍 Elided lifetimes.

Explanation

Async fns get transformed into methods that returnPin<Box<dyn Future + Send + 'async_trait>> and delegate to an async block.

For example theimpl Advertisement for AutoplayingVideo above would beexpanded as:

implAdvertisementforAutoplayingVideo{fnrun<'async_trait>(&'async_traitself,) ->Pin<Box<dyn std::future::Future<Output =()> +Send +'async_trait>>whereSelf:Sync +'async_trait,{Box::pin(asyncmove{/* the original method body */})}}

Non-threadsafe futures

Not all async traits need futures that aredyn Future + Send. To avoid havingSend and Sync bounds placed on the async trait methods, invoke the async traitmacro as#[async_trait(?Send)] on both the trait and the impl blocks.


Elided lifetimes

Be aware that async fn syntax does not allow lifetime elision outside of& and&mut references. (This is true even when not using #[async_trait].)Lifetimes must be named or marked by the placeholder'_.

Fortunately the compiler is able to diagnose missing lifetimes with a good errormessage.

typeElided<'a> =&'ausize;#[async_trait]traitTest{asyncfntest(not_okay:Elided,okay:&usize){}}
error[E0726]: implicit elided lifetime not allowed here --> src/main.rs:9:29  |9 |     async fn test(not_okay: Elided, okay: &usize) {}  |                             ^^^^^^- help: indicate the anonymous lifetime: `<'_>`

The fix is to name the lifetime or use'_.

#[async_trait]traitTest{// eitherasyncfntest<'e>(elided:Elided<'e>){}// orasyncfntest(elided:Elided<'_>){}}

License

Licensed under either ofApache License, Version2.0 orMIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submittedfor inclusion in this crate by you, as defined in the Apache-2.0 license, shallbe dual licensed as above, without any additional terms or conditions.

About

Type erasure for async trait methods

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors19

Languages


[8]ページ先頭

©2009-2025 Movatter.jp