2015-06-26 1 views
22

Leggendo il libro Rust, mi sono imbattuto in an interesting topic — divergent functions:Perché dovrei usare funzioni divergenti?

Rust ha una sintassi speciale per 'funzioni divergenti', che sono funzioni che non restituiscono:

fn diverges() -> ! { 
    panic!("This function never returns!"); 
} 

Una funzione divergente può essere utilizzata come qualsiasi tipo:

let x: i32 = diverges(); 
let x: String = diverges(); 

Quali sarebbero i casi d'uso di una funzione divergente? Il libro dice che

panic!() causa il thread corrente di esecuzione in crash con il dato messaggio. Poiché questa funzione causerà un incidente, non potrà mai di ritorno, e quindi ha il tipo !

che abbia un senso, ma non riesco a pensare a dove altro una funzione divergenti sarebbe di utilizzo e sembra molto localizzato a solo panic!. So che ci devono essere alcuni scenari utili là fuori per il motivo per cui hanno introdotto funzioni divergenti. Dove potrei vedere le funzioni divergenti in Rust?

risposta

31

Ha diversi usi. Può essere utilizzato per funzioni progettate per il panico o per uscire dal programma. panic!() è una di queste funzioni, ma può anche essere applicata a funzioni che includono panic!(), ad esempio la stampa di informazioni di errore più dettagliate e il panico.

Può essere utilizzato anche per funzioni che non ritornano mai. Se una funzione entra in un ciclo infinito, come il ciclo principale di un server, e quindi non ritorna mai, potrebbe essere definita in questo modo.

Un altro possibile utilizzo sarebbe un wrapper su Unix exec family of functions, in cui il processo corrente viene sostituito con quello in esecuzione.

È utile avere un tipo di questo tipo perché è compatibile con tutti gli altri tipi. Per essere sicuro, Rust deve garantire che tutti i rami di un'istruzione match o if restituiscano lo stesso tipo. Ma se ci sono alcuni rami irraggiungibili o che indicano un errore, è necessario un modo per lanciare un errore che si unificherà con il tipo restituito dagli altri rami. Poiché ! unifica con tutti i tipi, può essere utilizzato in qualsiasi caso.

C'è un interesting RFC (e discussion) nel momento in cui sostiene (in parte) per expanding the places where ! can be used, sostenendo che deve essere trattato come un tipo pieno titolo come () è; ! è un tipo senza valori che si unifica con tutti gli altri tipi, mentre () è un tipo distinto con un solo valore. Non sono sicuro di essere d'accordo con l'intero RFC, ma la discussione sul trattamento dello ! come tipo completo è interessante e penso che potrebbe essere proposta separatamente dal resto dell'RFC.

Aggiornamento: Da quando ho scritto quanto sopra, la parte del RFC di promuovere ! a un tipo pieno titolo era split into a separate RFC and merged, ed è in the process of being implemented (attualmente disponibile in nightly build dietro un cancello caratteristica). Come tipo completo, può essere utilizzato in più contesti, come ad esempio in Result<T, !> indicando un risultato che non può mai fallire, o Result<!, E> come uno che non può mai avere successo. Questi sono utili in contesti generici; se si dispone di un tratto che richiede un metodo per restituire un risultato, ma per quella particolare implementazione può solo avere esito positivo, non è necessario immettere un tipo di errore fittizio.

12

Come riportato dal libro, Rust's bottom type viene utilizzato per specificare le funzioni che non vengono restituite. Ciò include:

  • panic!()
  • loop per sempre
  • chiudere il programma (ad eccezione di ritorno da main()), come ad esempio exit(), la cui firma è pub fn exit(code: i32) -> !
+3

I miei preferiti sono 'non implementato!()' E 'non raggiungibile!()'. – Shepmaster