Da alcuni mesi, il rilascio notturno di Rust ha permesso di definire metodi asincroni per gli attributi. In precedenza, ciò richiedeva librerie aggiuntive. L’aggiornamento è una pietra miliare per il tanto atteso set di funzionalità asincrone di Rust. Ma quali sono i motivi dell’attesa e cosa deve accadere prima che i metodi asincroni negli attributi finiscano finalmente nella versione statica?
Zucchero sintattico per i futures
Per capire perché, dobbiamo iniziare con i principi di base della programmazione asincrona in Rust. Descrizione Ferris Talk No. 4 Funzione generale. Breve riassunto:
Rust non ha un ambiente di runtime asincrono integrato, ma si basa su librerie. Tuttavia, il linguaggio introduce costrutti di sintassi e funzionalità con cui le librerie possono lavorare.
Le caratteristiche includono con Future
Astratto un valore che arriverà ad un certo punto in futuro. Le funzioni che restituiscono futures non vengono eseguite immediatamente e le applicazioni devono inviarle esplicitamente a un ambiente di runtime asincrono o utilizzarle all’interno dell’esecuzione asincrona. .await
Aspettarsi.
Future
Un attributo che specifica il valore previsto utilizzando l’output del tipo associato. Ecco come possono essere descritti i valori restituiti.
trait Future {
type Output;
fn poll(self: Pin<&mut Self>,
cx: &mut Context<'_>) ->
Poll<Self::Output>;
}
sul metodo poll
Il runtime può dire se il valore esiste già o se è lo stesso valore Future
Per controllare più tardi.
Un’interfaccia di funzione asincrona che legge i dati in un buffer di stringhe e conta il numero di byte letti per ciascuno Result
I resi possono assomigliare a questo:
fn read_to_string(buf: &mut String) ->
impl Future<Output = Result<usize>>;
Rust utilizza la forma implicita dell’aggettivo, che descrive il ritorno dell’attributo Future
devono essere attuate e a Result
-enum con uno usize
Nel Ok
-Valore contenuto nell’output.
Questo costrutto può essere accorciato dallo zucchero sintattico usando la parola chiave async
davanti al lavoro. Il frammento di codice della funzione asincrona diventa in una notazione migliore:
async fn read_to_string(buf: &mut String)
-> Result<usize>;
Il compilatore Rust traduce questa sintassi in una variabile più complessa che gestisce i futures ed è quindi compatibile con ambienti di runtime asincroni.
Tipo di risoluzione per gli attributi
Come gestisci i tratti? Un piccolo disclaimer in anticipo: le decisioni dettagliate sullo zucchero sintattico possono deviare dalla realtà, ma fanno punti importanti.
L’esempio seguente definisce l’interfaccia di scrittura di un’applicazione di chat, in cui i dati possono essere inviati indipendentemente dall’effettiva implementazione.
pub trait ChatSink {
type Item: Clone;
async fn send_msg(&mut self,
msg: Self::Item) ->
Result<(), ChatCommErr>;
}
La tokenizzazione tramite contratti future rivela alcuni punti deboli.
Passaggio 1: rimuovere la parola chiave async e sostituirla con receiver.
pub trait ChatSink {
type Item: Clone;
fn send_msg(&mut self, msg: Self::Item) ->
impl Future<Output = Result<(), ChatCommErr>>;
}
Sebbene il codice sembri utilizzabile a prima vista, il compilatore Rust non lo accetta. nelle caratteristiche attuali Non ci sono ancora attributi impliciti consentiti nelle posizioni di reso. In Nightly Rust, questa è un’altra caratteristica che può essere facilmente attivata con una macro, ma porta al seguente problema: anche l’attributo implicito nei metodi è lo zucchero della sintassi. In effetti, il compilatore crea un tipo associato:
pub trait ChatSink {
type Item: Clone;
type $: Future<Output = Result<(), ChatCommErr>>;
fn send_msg(&mut self, msg: Self::Item) -> Self::$;
}
Non sembra molto eccitante, ma fa luce su qualcosa di importante che finora è stato ignorato: l’era futura.
“Esperto di birra per tutta la vita. Appassionato di viaggi in generale. Appassionato di social media. Esperto di zombi. Comunicatore.”