2016-04-27 41 views
11

In Rust, credo che il modo idiomatico per gestire gli errori recuperabili sia utilizzare Result. Ad esempio questa funzione è chiaramente idiomatica:Qual è il modo idiomatico per restituire un errore da una funzione senza risultato se ha esito positivo?

fn do_work() -> Result<u64, WorkError> {...} 

Naturalmente, ci sono anche funzioni che hanno un unico, evidente, stato di avaria, e quindi utilizzano il tipo di opzione. Un esempio idiomatico sarebbe questo:

fn do_work() -> Option<u64> 

Tutto questo è indirizzato direttamente nella documentazione. Tuttavia, sono confuso sul caso in cui una funzione può fallire, ma non ha alcun valore significativo quando ha successo. Confrontare le seguenti due funzioni:

fn do_work() -> Option<WorkError> 
// vs 
fn do_work() -> Result<(), WorkError> 

Non sono solo sicuro che uno di questi è più idiomatica, o è usato più spesso nel codice Rust mondo reale. La mia risorsa go-to per domande come questa è il libro Rust, ma non penso che questo sia affrontato nella sua sezione "Error Handling". Nemmeno io ho avuto molta fortuna con nessun'altra documentazione di Rust.

Ovviamente questo sembra piuttosto soggettivo, ma sto cercando fonti autorevoli che stabiliscano quale forma sia idiomatica, o sul perché una forma sia superiore (o inferiore) all'altra. (Sono anche curioso di sapere come la convenzione paragona ad altre lingue che utilizzano pesantemente "errori come valori", come Go e Haskell.)

+2

Io sono del lato 'Risultato <(), Error> '. Di solito li alias anche come miei tipi. Sarei interessato a sapere cosa dicono gli altri. Lo faccio anche perché la macro 'try!' Funziona ancora molto bene con esso. –

risposta

17

Utilizzare fn do_work() -> Result<(), WorkError>.

Result<(), WorkError> significa che si desidera eseguire il lavoro, ma potrebbe non riuscire.

Option<WorkError> significa che si desidera ottenere un errore, ma potrebbe essere assente.

Probabilmente vuoi che il lavoro sia finito ma non per ottenere un errore quando scrivi do_work(), quindi Result<(), WorkError> è la scelta migliore.

Mi aspetto che Option<WorkError> sia utilizzato solo in casi come fn get_last_work_error() -> Option<WorkError>.

+0

Non credo di non essere d'accordo, penso che Result <(), WorkError> sia leggermente più bello. Tuttavia, mi chiedo se ci sono fonti "ufficiali" che supportano la tua risposta in alcun modo? – Others

+0

@Altri Poiché 'do_work' è di per sé un esempio concettuale, non mi aspetto che ci sarà alcuna convenzione ufficiale per questo. Ma puoi avere un'idea dell'idioma nella libreria standard, ad esempio: https://doc.rust-lang.org/nightly/std/io/trait.Read.html#method.read_exact – WiSaGaN

+4

@Altra l'intera libreria standard usa 'Result <(), _>' pervasivamente quando un'operazione che può fallire non restituisce nulla di utile (ad es. molte funzioni di 'std :: io' e' std :: fs'). È la scelta giusta – huon

4

Rust è "abbastanza fortemente digitato" (e per favore, per favore non chiamarmi su come misuro quanto sia tipicamente tipizzato un linguaggio ...). Intendo questo nel senso che Rust generalmente ti dà gli strumenti per lasciare che i tipi "parlano" per te e documentino il tuo codice, quindi è idiomatico usare questa funzione per scrivere codice leggibile.

In altre parole, la domanda che stai chiedendo dovrebbe essere più "quale tipo rappresenta meglio ciò che la funzione fa a chiunque legga la sua firma?"

Per Result<(), Workerror> si può vedere direttamente from the docs

risultato è un tipo che rappresenta sia il successo (OK) o negativo (Err)

Così, specializzata per il vostro caso, significa la funzione restituisce nulla se ha successo (rappresentato da Ok<()>) o WorkError se c'è un errore (Err<WorkError>). Questa è una rappresentazione molto diretta nel codice del modo in cui hai descritto la funzione nella tua domanda.

confrontare questo a Option<WorkError> o Option<()>

Tipo opzione rappresenta un valore facoltativo: ogni opzione è o alcuni e contiene un valore o None, e non

Nel tuo caso Option<WorkError> sarebbe dicendo al lettore "questa funzione dovrebbe restituire un WorkError ma potrebbe non restituire nulla". Puoi documentare che il caso "return nothing" significa che la funzione ha avuto effettivamente successo, ma questo non è molto evidente dai soli tipi.

Option<()> dice "questa funzione può restituire nulla o non hanno alcun ritorno significativo", che può essere una cosa ragionevole da dire se WorkError non contiene altre informazioni (come un tipo di errore o un messaggio di errore) ed è praticamente solo un modo per dì "si è verificato un errore". In questo caso un semplice bool trasporta le stesse informazioni ... In caso contrario, lo Result consente di restituire ulteriori informazioni associate all'errore.