2015-06-26 9 views
22

Czytając książki Rust, natknąłem an interesting topic — divergent functions:Dlaczego miałbym używać funkcji rozbieżnych?

Rust ma jakąś specjalną składnię dla 'funkcji rozbieżne', które należą funkcje, które nie zwracają:

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

Funkcja rozbieżności może być używana jako dowolny typ:

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

Jakie byłyby przypadki użycia funkcji rozbieżności? Książka mówi, że

panic!() powoduje obecny wątek wykonania do zderzenia z danej wiadomości. Ponieważ funkcja ta spowoduje katastrofę, to nigdy zwrotu, a więc ma typ !

to ma sens, ale nie mogę myśleć gdzie indziej rozbieżne funkcja byłaby obsługi i wydaje bardzo zlokalizowane na tylko panic!. Wiem, że muszą istnieć przydatne scenariusze, dla których wprowadzono rozbieżne funkcje. Gdzie prawdopodobnie będę widział rozbieżne funkcje w Rust?

Odpowiedz

31

Ma ona kilka zastosowań. Może być używany do funkcji, które są zaprojektowane do paniki lub wyjścia z programu. panic!() sama jest jedną z takich funkcji, ale można ją również zastosować do funkcji, które obejmują panic!(), takich jak drukowanie bardziej szczegółowych informacji o błędach, a następnie panikowanie.

Może być również używany do funkcji, które nigdy nie powrócą. Jeśli funkcja przechodzi do nieskończonej pętli, takiej jak główna pętla serwera, a zatem nigdy nie wraca, może zostać zdefiniowana w ten sposób.

Innym możliwym zastosowaniem będzie opakowanie wokół Unixa exec family of functions, w którym bieżący proces zostanie zastąpiony bieżącym procesem.

Przydaje się taki typ, ponieważ jest zgodny z wszystkimi innymi typami. Aby być bezpiecznym w typie, Rust musi upewnić się, że wszystkie gałęzie oświadczenia match lub if zwracają ten sam typ. Ale jeśli istnieją jakieś gałęzie, które są nieosiągalne lub wskazują na błąd, potrzebny jest sposób na zgłoszenie błędu, który zostanie ujednolicony z typem zwracanym przez inne gałęzie. Ponieważ ! ujednolica ze wszystkimi typami, może być użyty w każdym takim przypadku.

Jest interesting RFC (i discussion) w chwili, gdy twierdzi, (w części) do expanding the places where ! can be used, twierdząc, że powinna być traktowana jako w pełni rozwiniętym typu jak () IS; ! jest typem bez wartości jednoczących się ze wszystkimi pozostałymi typami, natomiast () jest typem odrębnym o pojedynczej wartości. Nie jestem pewien, czy zgadzam się z pełnym RFC, ale dyskusja o traktowaniu ! jako typu pełnoprawnego jest interesująca i myślę, że mogłaby być zaproponowana oddzielnie od reszty specyfikacji RFC.

Aktualizacja: Ponieważ napisałem wyżej, część RFC o promowanie ! do pełnego typu rozwiniętego był split into a separate RFC and merged i jest in the process of being implemented (obecnie dostępny w nightly buduje za bramą fabularnym). Jako pełnoprawny typ można go stosować w większej liczbie kontekstów, na przykład w Result<T, !>, wskazując wynik, który nigdy nie zawiedzie, lub Result<!, E> jako taki, który nigdy nie może się powieść. Są użyteczne w ogólnych kontekstach; jeśli masz jakąś cechę, która wymaga metody zwracania wyniku, ale dla tej konkretnej implementacji może się to tylko udać, nie musisz wypełniać jakiegoś fałszywego typu błędu.

12

Jak zacytowano w książce, Rust bottom type służy do określenia funkcji, które nie powracają. Obejmuje to:

  • panic!()
  • pętli zawsze
  • wychodzenia z programu (z wyjątkiem powrocie z main()), takie jak exit(), którego podpis znajduje pub fn exit(code: i32) -> !
+3

Moje ulubione to 'unimplemented!()' I 'unreachable!()'. – Shepmaster

Powiązane problemy