Funcții Asincrone în Trait-uri (AFIT) și Return-Position Impl Trait (RPITIT) în Rust în Rust

Ghid complet pentru funcțiile asincrone native în trait-uri (AFIT) introduse în Rust 1.75+: eliminarea alocărilor de heap din crate-ul async-trait, mecanismul RPITIT și garantarea constrângerilor de fir Send.

Sintaxă
trait Database { async fn query(&self, sql: &str) -> Result<Row, DbError>; }

Timp de mulți ani, una dintre cele mai mari limitări din ecosistemul asincron Rust a fost imposibilitatea de a defini direct async fn în interiorul unui trait. Dezvoltatorii erau nevoiți să recurgă la macro-ul extern #[async_trait], care transforma fiecare apel de metodă într-o alocare forțată pe heap (Box) cu dispatch dinamic și penalizare de performanță.

Începând cu Rust 1.75, compilatorul suportă nativ Async fn in Traits (AFIT) și Return-Position Impl Trait in Trait (RPITIT). Compilatorul sintetizează automat un tip asociat anonim generat pentru fiecare funcție asincronă, păstrând dispatch-ul static și principiul Zero-Cost Abstractions fără nicio alocare de heap!

Definirea și Implementarea unui Trait Asincron Nativ
// 1. Declararea trait-ului cu funcție asincronă nativă (fără macro-uri externe!):
pub trait ServiciuStocare {
    async fn salveaza_date(&self, id: u64, payload: &[u8]) -> Result<(), std::io::Error>;
    async fn citeste_date(&self, id: u64) -> Result, std::io::Error>;
}

// 2. Structura concretă care implementează trait-ul:
pub struct StocareMemorie;

impl ServiciuStocare for StocareMemorie {
    async fn salveaza_date(&self, id: u64, payload: &[u8]) -> Result<(), std::io::Error> {
        // Operație asincronă nativă pe stivă:
        println!("Salvat {} octeți pentru ID-ul {}", payload.len(), id);
        Ok(())
    }

    async fn citeste_date(&self, id: u64) -> Result, std::io::Error> {
        Ok(vec![1, 2, 3, 4])
    }
}

// 3. Consumul funcției generice:
pub async fn executa_backup(stocare: &T) {
    let date = [0xAA, 0xBB, 0xCC];
    let _ = stocare.salveaza_date(101, &date).await;
}

Gestionarea Constrângerii Send în Runtimes Multi-Thread

În runtime-uri asincrone distribuite pe thread pool (cum ar fi Tokio multi-thread), viitorul (Future) generat de o funcție dintr-un trait trebuie să poată fi transferat în siguranță între fire (să implementeze Send). Pentru a asigura compatibilitatea, putem folosi constrângeri explicite:

pub trait ServiciuWeb {
    // Declarare explicită a compatibilității cu thread pool-uri paralele:
    fn fetch(&self) -> impl std::future::Future + Send;
}