diff --git a/src/concurrency/async-pitfalls/async-traits.md b/src/concurrency/async-pitfalls/async-traits.md index 5b285ec1..8d552052 100644 --- a/src/concurrency/async-pitfalls/async-traits.md +++ b/src/concurrency/async-pitfalls/async-traits.md @@ -4,22 +4,20 @@ minutes: 5 # Async Traits -Async methods in traits are were stabilized only recently, in the 1.75 release. -This required support for using return-position `impl Trait` (RPIT) in traits, -as the desugaring for `async fn` includes `-> impl Future`. +Async methods in traits are were stabilized in the 1.75 release. This required +support for using return-position `impl Trait` in traits, as the desugaring for +`async fn` includes `-> impl Future`. -However, even with the native support today there are some pitfalls around -`async fn` and RPIT in traits: +However, even with the native support, there are some pitfalls around +`async fn`: -- Return-position impl Trait captures all in-scope lifetimes (so some patterns - of borrowing cannot be expressed) +- Return-position `impl Trait` captures all in-scope lifetimes (so some patterns + of borrowing cannot be expressed). -- Traits whose methods use return-position `impl trait` or `async` are not `dyn` - compatible. +- Async traits cannot be used with [trait objects] (`dyn Trait` support). -If we do need `dyn` support, the crate -[async_trait](https://docs.rs/async-trait/latest/async_trait/) provides a -workaround through a macro, with some caveats: +The [async_trait] crate provides a workaround for `dyn` support through a macro, +with some caveats: ```rust,editable,compile_fail use async_trait::async_trait; @@ -47,11 +45,11 @@ async fn run_all_sleepers_multiple_times( n_times: usize, ) { for _ in 0..n_times { - println!("running all sleepers.."); + println!("Running all sleepers..."); for sleeper in &sleepers { let start = Instant::now(); sleeper.sleep().await; - println!("slept for {}ms", start.elapsed().as_millis()); + println!("Slept for {} ms", start.elapsed().as_millis()); } } } @@ -71,13 +69,21 @@ async fn main() { - `async_trait` is easy to use, but note that it's using heap allocations to achieve this. This heap allocation has performance overhead. -- The challenges in language support for `async trait` are deep Rust and - probably not worth describing in-depth. Niko Matsakis did a good job of - explaining them in - [this post](https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/) - if you are interested in digging deeper. +- The challenges in language support for `async trait` are too deep to describe + in-depth in this class. See [this blog post] by Niko Matsakis if you are + interested in digging deeper. See also these keywords: + + - [RPIT]: short for + [return-position `impl Trait`](../../generics/impl-trait.md). + - [RPITIT]: short for return-position `impl Trait` in trait (RPIT in trait). - Try creating a new sleeper struct that will sleep for a random amount of time - and adding it to the Vec. + and adding it to the `Vec`. + +[async_trait]: https://docs.rs/async-trait/ +[trait objects]: ../../smart-pointers/trait-objects.md +[this blog post]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ +[RPIT]: https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types +[RPITIT]: https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html