Async Traits
Recipe | Crates | Categories |
---|---|---|
Async Traits |
As of Rust 1.75, it is possible to have async
⮳ functions in traits:
struct MyHealthChecker; /// A trait for checking the health of a system. trait HealthCheck { /// Checks the health of the system. /// /// Returns `true` if the system is healthy, `false` otherwise. async fn check(&mut self) -> bool; } impl HealthCheck for MyHealthChecker { // `async fn` implementation in the associated `impl` block. async fn check(&mut self) -> bool { do_async_op().await } } async fn do_health_check(mut hc: impl HealthCheck) { if !hc.check().await { // Use as normal. log_health_check_failure().await; } else { println!("Health check was normal"); } } async fn do_async_op() -> bool { true } async fn log_health_check_failure() { println!("Health check failure"); } #[tokio::main] async fn main() { let hc = MyHealthChecker; do_health_check(hc).await; }
[Stabilizing async fn in traits in 2023]blog-stabilizing-async-fn-in-traits⮳.
This is in turn enabled by return-position impl Trait
in traits, since async fn
is sugar for functions that return -> impl Future
.
/// This example demonstrates how to use `impl Trait` in a trait definition. /// /// The `Container` trait defines a method `items` that returns /// an iterator over `u8` values. The specific type of the iterator is not /// specified in the trait definition, but is instead left to the implementor /// to decide. #[allow(dead_code)] trait Container { /// Returns an iterator over the items in the container. fn items(&self) -> impl Iterator<Item = u8>; } /// A concrete implementation of the `Container` trait. struct MyContainer { items: Vec<u8>, } /// Implementation of the `Container` trait for `MyContainer`. impl Container for MyContainer { fn items(&self) -> impl Iterator<Item = u8> { self.items.iter().cloned() } } fn main() { let c = MyContainer { items: vec![1, 2, 3], }; for i in c.items { println!("{}", i); } }
Note that there are still caveats for public traits - see [Announcing [async][p-async] fn
and return-position impl Trait
in traits]blog-announcing-async-fn⮳.
In addition, traits that use -> impl Trait
and [async][p-async] fn
are not object-safe, which means they lack support for dynamic dispatch. In the meanwhile, use the async-trait
⮳ crate.
use async_trait::async_trait; // Define an asynchronous trait named `Advertisement`. #[async_trait] trait Advertisement { async fn run(&self); } struct Modal; // Implement the `Advertisement` trait for the `Modal` struct. #[async_trait] impl Advertisement for Modal { async fn run(&self) { // Call the `render_fullscreen` method on `self` and await its // completion. self.render_fullscreen().await; // Loop 4 times. for _ in 0..4u16 { // Call the `remind_user_to_join_mailing_list` function and await // its completion. remind_user_to_join_mailing_list().await; } // Call the `hide_for_now` method on `self` and await its completion. self.hide_for_now().await; } } // Implement methods for the `Modal` struct. impl Modal { async fn render_fullscreen(&self) { println!("Render fullscreen"); } async fn hide_for_now(&self) { println!("Hide for now"); } } async fn remind_user_to_join_mailing_list() { println!("Please join our mailing list"); } #[tokio::main] async fn main() { // Create an instance of `Modal` and call the `run` method, awaiting its // completion. Modal.run().await; }
Related Topics
- Trait Objects.
- Traits.