Elixir - obsługa błędów
Elixir ma trzy mechanizmy błędów: błędy, wyrzuty i wyjścia. Przyjrzyjmy się szczegółowo każdemu mechanizmowi.
Błąd
Błędy (lub wyjątki) są używane, gdy w kodzie zdarzają się wyjątkowe rzeczy. Przykładowy błąd można pobrać, próbując dodać liczbę do ciągu -
IO.puts(1 + "Hello")
Uruchomienie powyższego programu powoduje następujący błąd -
** (ArithmeticError) bad argument in arithmetic expression
:erlang.+(1, "Hello")
To był przykładowy wbudowany błąd.
Podnoszenie błędów
Możemy raisebłędy przy użyciu funkcji podbijania. Rozważmy przykład, aby zrozumieć to samo -
#Runtime Error with just a message
raise "oops" # ** (RuntimeError) oops
Inne błędy można wywołać, przekazując podbicie / 2 nazwę błędu i listę argumentów słów kluczowych
#Other error type with a message
raise ArgumentError, message: "invalid argument foo"
Możesz także zdefiniować własne błędy i je zgłosić. Rozważmy następujący przykład -
defmodule MyError do
defexception message: "default message"
end
raise MyError # Raises error with default message
raise MyError, message: "custom message" # Raises error with custom message
Ratowanie błędów
Nie chcemy, aby nasze programy nagle się kończyły, ale raczej musimy ostrożnie obchodzić się z błędami. W tym celu używamy obsługi błędów. Myrescue błędy przy użyciu try/rescuezbudować. Rozważmy następujący przykład, aby zrozumieć to samo -
err = try do
raise "oops"
rescue
e in RuntimeError -> e
end
IO.puts(err.message)
Uruchomienie powyższego programu daje następujący wynik -
oops
Obsługiwaliśmy błędy w instrukcji ratunkowej, używając dopasowywania wzorców. Jeśli nie wykorzystujemy w żaden sposób błędu, a po prostu chcemy go wykorzystać do celów identyfikacji, możemy również skorzystać z formularza -
err = try do
1 + "Hello"
rescue
RuntimeError -> "You've got a runtime error!"
ArithmeticError -> "You've got a Argument error!"
end
IO.puts(err)
Uruchomienie powyższego programu daje następujący wynik -
You've got a Argument error!
NOTE- Większość funkcji w standardowej bibliotece Elixir jest zaimplementowanych dwukrotnie, raz zwracając krotki, a raz generując błędy. Na przykładFile.read i File.read!Funkcje. Pierwsza zwróciła krotkę, jeśli plik został pomyślnie odczytany i jeśli napotkano błąd, ta krotka została użyta do podania przyczyny błędu. Drugi powodował błąd, jeśli wystąpił błąd.
Jeśli użyjemy pierwszego podejścia do funkcji, musimy użyć przypadku dla wzorca dopasowującego błąd i podjąć działania zgodnie z tym. W drugim przypadku używamy metody try rescue dla kodu podatnego na błędy i odpowiednio je obsługujemy.
Rzuty
W Elixirze wartość można rzucić, a później złapać. Rzut i złapanie są zarezerwowane dla sytuacji, w których nie można odzyskać wartości, chyba że za pomocą rzutu i złapania.
Wystąpienia są w praktyce dość rzadkie, z wyjątkiem interakcji z bibliotekami. Na przykład załóżmy teraz, że moduł Enum nie zapewnił żadnego interfejsu API do znajdowania wartości i że potrzebowaliśmy znaleźć pierwszą wielokrotność 13 na liście liczb -
val = try do
Enum.each 20..100, fn(x) ->
if rem(x, 13) == 0, do: throw(x)
end
"Got nothing"
catch
x -> "Got #{x}"
end
IO.puts(val)
Uruchomienie powyższego programu daje następujący wynik -
Got 26
Wyjście
Kiedy proces umiera z „przyczyn naturalnych” (na przykład nieobsłużonych wyjątków), wysyła sygnał wyjścia. Proces może również umrzeć przez jawne wysłanie sygnału wyjścia. Rozważmy następujący przykład -
spawn_link fn -> exit(1) end
W powyższym przykładzie połączony proces przestał działać, wysyłając sygnał wyjścia o wartości 1. Zauważ, że wyjście można również „złapać” za pomocą try / catch. Na przykład -
val = try do
exit "I am exiting"
catch
:exit, _ -> "not really"
end
IO.puts(val)
Uruchomienie powyższego programu daje następujący wynik -
not really
Po
Czasami trzeba upewnić się, że zasób został wyczyszczony po wykonaniu jakiejś czynności, która może potencjalnie spowodować błąd. Konstrukcja try / after pozwala ci to zrobić. Na przykład, możemy otworzyć plik i użyć klauzuli after, aby go zamknąć - nawet jeśli coś pójdzie nie tak.
{:ok, file} = File.open "sample", [:utf8, :write]
try do
IO.write file, "olá"
raise "oops, something went wrong"
after
File.close(file)
end
Gdy uruchomimy ten program, wyświetli się błąd. Aleafter oświadczenie zapewni, że deskryptor pliku zostanie zamknięty po każdym takim zdarzeniu.