Pillole di rust: gestire closure che possono fallire

Il problema

In un mio progetto scritto con il linguaggio Rust (un’utilità a riga di comando chiamata timetrack) avevo bisogno di convertire una stringa in una data. Il tipo di partenza era &Option<String>, mentre il tipo che volevo raggiungere era Option<Datetime>. Per effettuare operazioni sui valori all’interno di un Option, possiamo usare la funzione .map(), passandogli una closure. L’unico problema era che la funzione per convertire la stringa in una data avrebbe potuto fallire, quindi ritornava un valore Result. Volevo mantenere un codice conciso che mi permettesse di fare il bubble-up dell’errore, ma inizialmente il fatto di avere il valore Result annidato all’interno dell’Option mi aveva bloccato per un po’.

Una soluzione spiacevole

Una possibilità era quella di estrarre il valore facendo un match:

// la variabile `at` è il valore che volevo convertire, ha il tipo `&Option<String>`
// `.as_ref()` serve solo per trasformare `&Option<T>` in `Option<&T>`.
let parsed_result = at.as_ref().map(|time_str| parse(time_str));

let target_time = match parsed_result {
    Some(Ok(res)) => Some(res), // Estraiamo il valore se è tutto ok
    Some(Err(e)) => return Err(e), // Interrompiamo l'esecuzione e ritorniamo l'errore se ha fallito
    None => None
};

Una soluzione idiomatica

Una soluzione più idiomatica e concisa consiste nell’usare la funzione transpose(). Questa funzione converte Option<Result<T>> in Result<Option<T>> (e viceversa). Dopo aver effettuato la trasposizione, possiamo semplicemente usare l’operatore ? per ritornare l’errore nel caso che l’operazione all’interno della closure fallisca.

Quindi ecco la seconda, migliore, soluzione:

let target_time = at.as_ref()
                    .map(|time_str| parse(time_str))
                    .transpose()?;

Questo è più o meno il codice che ho utilizzato in vari punti del mio progetto, fra cui questa riga nel file principale.

Pillole di rust

Questa nuova rubrica si distoglie un po’ dagli argomenti che tratto generalmente nel mio sito. Comunque, ultimamente sto programmando parecchio in Rust per dei progetti personali, e mi sto trovando davvero bene!

Quindi, ho deciso di condividere ogni tanto qualche chicca che scopro mentre continuo la mia immersione in questo linguaggio. Generalmente, saranno piccoli suggerimenti e scoperte utili a sviluppatori rust intermedi. In pratica, se siete nuovi al linguaggio Rust, questi articoli potrebbero confondervi, mentre se siete molto esperti probabilmente queste cose le saprete già. Comunque, immagino ci siano diversi sviluppatori che, come me, si ritrovano nel mezzo.

Spero possa piacervi!