Asyncトレイト
トレイト内の async メソッドは、1.75 リリースで安定化されました。これには、トレイト内で戻り値位置の impl Trait を使うためのサポートが必要でした。async fn の脱糖では -> impl Future<Output = ...> が含まれるためです。
しかし、ネイティブサポートがあっても、async fn にはいくつか特有の落とし穴があります。
-
戻り値位置の
impl Traitは、スコープ内のすべてのライフタイムをキャプチャします(そのため、特定の借用パターンは表現できません)。 -
async トレイトは trait objects と一緒には使えません(
dyn Traitはサポートされません)。
async_trait クレートは、いくつかの注意点はあるものの、マクロを通じて dyn サポートの回避策を提供します。
// Copyright 2024 Google LLC // SPDX-License-Identifier: Apache-2.0 use async_trait::async_trait; use std::time::Instant; use tokio::time::{Duration, sleep}; #[async_trait] trait Sleeper { async fn sleep(&self); } struct FixedSleeper { sleep_ms: u64, } #[async_trait] impl Sleeper for FixedSleeper { async fn sleep(&self) { sleep(Duration::from_millis(self.sleep_ms)).await; } } async fn run_all_sleepers_multiple_times( sleepers: Vec<Box<dyn Sleeper>>, n_times: usize, ) { for _ in 0..n_times { println!("Running all sleepers..."); for sleeper in &sleepers { let start = Instant::now(); sleeper.sleep().await; println!("Slept for {} ms", start.elapsed().as_millis()); } } } #[tokio::main] async fn main() { let sleepers: Vec<Box<dyn Sleeper>> = vec![ Box::new(FixedSleeper { sleep_ms: 50 }), Box::new(FixedSleeper { sleep_ms: 100 }), ]; run_all_sleepers_multiple_times(sleepers, 5).await; }
-
async_traitは簡単に使えますが、これを実現するためにヒープ割り当てを使っている点に注意してください。このヒープ割り当てには性能上のオーバーヘッドがあります。 -
async traitの言語サポートに関する課題は、この授業で詳しく説明するにはあまりにも深いものです。さらに掘り下げたい場合は、Niko Matsakis による this blog post を参照してください。次のキーワードも参照してください。- RPIT: 戻り値位置の
impl Traitの略。 - RPITIT: トレイト内の戻り値位置
impl Trait(トレイト内 RPIT)の略。
- RPIT: 戻り値位置の
-
ランダムな時間だけスリープする新しい sleeper 構造体を作成し、それを
Vecに追加してみてください。