2016-04-27 11 views
11

W Rust uważam, że idiomatycznym sposobem radzenia sobie z możliwymi do naprawienia błędami jest użycie wyniku. Na przykład funkcja ta wyraźnie jest idiomatyczne:Jaki jest idiomatyczny sposób zwracania błędu z funkcji bez wyniku, jeśli zakończy się powodzeniem?

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

Oczywiście, istnieją również funkcje, które mają jedną, oczywistą, stan awarii i dlatego używają typu opcji zamiast. Idiomatyczny przykład to:

fn do_work() -> Option<u64> 

Wszystko to jest bezpośrednio omówione w dokumentacji. Jestem jednak zdezorientowany przypadkiem, w którym funkcja może się nie powieść, ale nie ma znaczącej wartości, gdy się powiedzie. Porównaj dwa następujące funkcje:

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

ja po prostu nie jestem pewien, który jeden z nich jest bardziej idiomatyczne, czy jest używana częściej w świecie rzeczywistym kodzie Rust. Moim głównym źródłem pytań na ten temat jest książka "Rdza", ale nie sądzę, że jest to omówione w sekcji "Error Handling". Nie miałem też szczęścia w żadnej innej dokumentacji Rusta.

Oczywiście wydaje się to dość subiektywne, ale szukam autorytatywnych źródeł, które stwierdzają, która forma jest idiomatyczna, lub dlaczego jedna forma jest lepsza (lub gorsza) od drugiej. (Jestem także ciekawy, jak konwencja jest porównywana z innymi językami, które w dużym stopniu wykorzystują "błędy jako wartości", takie jak Go i Haskell.)

+2

Jestem z 'Result <(), Error>' strony rzeczy .. Zazwyczaj pseudonimem te są również moje własne typy. Chciałbym usłyszeć, co mówią inni. Robię to jednak, ponieważ makra 'try!' Nadal bardzo dobrze z nim grają. –

Odpowiedz

17

Użyj fn do_work() -> Result<(), WorkError>.

Result<(), WorkError> oznacza, że ​​chcesz, aby praca została wykonana, ale może się nie udać.

Option<WorkError> oznacza, że ​​chcesz uzyskać błąd, ale może być nieobecny.

Prawdopodobnie chcesz, aby praca została wykonana, ale nie pomyl się, pisząc do_work(), więc lepszym wyborem jest .

Spodziewam się, że Option<WorkError> będzie używane tylko w przypadkach takich jak fn get_last_work_error() -> Option<WorkError>.

+0

Nie sądzę, nie zgadzam się, myślę, że wynik <(), WorkError> jest nieco ładniejszy. Zastanawiam się jednak, czy istnieją jakieś "oficjalne" źródła, które w jakikolwiek sposób wspierają twoją odpowiedź? – Others

+0

@Inne Ponieważ 'do_work' sam w sobie jest konceptualnym przykładem, nie spodziewam się, że będzie jakaś oficjalna konwencja. Ale można uzyskać pojęcie idiomu w standardowej bibliotece, na przykład: https://doc.rust-lang.org/nightly/std/io/trait.Read.html#method.read_exact – WiSaGaN

+4

@Inna jest cała standardowa biblioteka używa 'Result <(), _>' pervasively, gdy operacja, która może zawieść, nie zwraca niczego użytecznego (np. wiele funkcji 'std :: io' i' std :: fs'). To jest właściwy wybór. – huon

4

Rdza jest "dość mocno napisana" (i proszę, nie wzywajcie mnie, jak mierzę, jak mocno napisany jest język ...). Mam na myśli to w tym sensie, że Rust ogólnie daje narzędzia pozwalające typom "mówić" za ciebie i dokumentować twój kod, dlatego jest to idiomatyczne, aby użyć tej funkcji do napisania czytelnego kodu.

Innymi słowy, pytanie, które zadajesz, powinno być bardziej "jaki typ najlepiej odpowiada funkcji, jaką spełnia każda osoba, która czyta jej podpis?"

Dla Result<(), Workerror> można zobaczyć prosto from the docs

Wynik jest typem, który reprezentuje zarówno sukces (OK) lub awarii (Err)

Tak, wyspecjalizowana w Twoim przypadku, to znaczy swoją funkcję nic nie zwraca, jeśli zakończy się pomyślnie (reprezentowana przez Ok<()>) lub WorkError, jeśli wystąpił błąd (Err<WorkError>). Jest to bardzo bezpośrednia reprezentacja w kodzie sposobu, w jaki opisałeś funkcję w swoim pytaniu.

Porównaj to do Option<WorkError> lub Option<()>

typu opcji oznacza ewentualne wartości: każda opcja jest albo jednych i zawiera wartość lub Brak i nie

robi w twoim przypadku Option<WorkError> byłoby mówiąc do czytelnika "ta funkcja powinna zwrócić wartość WorkError, ale może ona nie zwrócić nic". Możesz udokumentować, że przypadek "nic nie zwracaj" oznacza, że ​​funkcja faktycznie odniosła sukces, ale nie jest to bardzo oczywiste z samych typów.

Option<()> mówi „ta funkcja może powrócić nic lub nie mają znaczącego zwrotu”, który może być rozsądnym rozwiązaniem powiedzieć jeśli WorkError nie zawiera żadnych innych informacji (jak typ błędu lub komunikat o błędzie) i jest to praktycznie jedyny sposób na powiedz "wystąpił błąd". W tym przypadku prosty bool przenosi te same informacje ... W przeciwnym razie Result pozwala ci zwrócić więcej informacji związanych z błędem.

Powiązane problemy