Асинхронные трейты
Асинхронные методы в трейтах были стабилизированы в релизе 1.75. Для этого потребовалась поддержка impl Trait в возвращаемой позиции внутри трейтов, так как десахаризация async fn включает -> impl Future<Output = ...>.
Однако даже при нативной поддержке есть особые подводные камни, связанные с async fn:
-
impl Traitв возвращаемой позиции захватывает все времена жизни из области видимости (поэтому некоторые шаблоны заимствования нельзя выразить). -
Асинхронные трейты нельзя использовать с объектами трейтов (нет поддержки
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слишком глубоки, чтобы подробно описывать их на этом занятии. Если хотите разобраться глубже, см. эту запись в блоге Ники Мацакиса. Также см. эти ключевые слова:- RPIT: сокращение от
impl Traitв возвращаемой позиции. - RPITIT: сокращение от
impl Traitв возвращаемой позиции внутри трейта (RPIT in trait).
- RPIT: сокращение от
-
Попробуйте создать новую структуру «спящего», которая будет спать случайное время, и добавить её в
Vec.