Elixier - Fehlerbehandlung

Elixir hat drei Fehlermechanismen: Fehler, Würfe und Exits. Lassen Sie uns jeden Mechanismus im Detail untersuchen.

Error

Fehler (oder Ausnahmen) werden verwendet, wenn außergewöhnliche Dinge im Code passieren. Ein Beispielfehler kann abgerufen werden, indem versucht wird, einer Zeichenfolge eine Zahl hinzuzufügen.

IO.puts(1 + "Hello")

Wenn das obige Programm ausgeführt wird, wird der folgende Fehler ausgegeben:

** (ArithmeticError) bad argument in arithmetic expression
   :erlang.+(1, "Hello")

Dies war ein eingebauter Beispielfehler.

Fehler auslösen

Wir können raiseFehler bei der Verwendung der Erhöhungsfunktionen. Betrachten wir ein Beispiel, um dasselbe zu verstehen -

#Runtime Error with just a message
raise "oops"  # ** (RuntimeError) oops

Andere Fehler können ausgelöst werden, indem Raise / 2 den Fehlernamen und eine Liste von Schlüsselwortargumenten übergibt

#Other error type with a message
raise ArgumentError, message: "invalid argument foo"

Sie können auch Ihre eigenen Fehler definieren und diese auslösen. Betrachten Sie das folgende Beispiel -

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

Fehler beheben

Wir möchten nicht, dass unsere Programme abrupt beendet werden, sondern dass die Fehler sorgfältig behandelt werden. Hierfür verwenden wir die Fehlerbehandlung. Wirrescue Fehler bei der Verwendung der try/rescuebauen. Betrachten wir das folgende Beispiel, um dasselbe zu verstehen:

err = try do
   raise "oops"
rescue
   e in RuntimeError -> e
end

IO.puts(err.message)

Wenn das obige Programm ausgeführt wird, wird das folgende Ergebnis erzeugt:

oops

Wir haben Fehler in der Rettungsanweisung mithilfe des Mustervergleichs behandelt. Wenn wir den Fehler nicht verwenden und ihn nur zu Identifikationszwecken verwenden möchten, können wir auch das Formular verwenden -

err = try do
   1 + "Hello"
rescue
   RuntimeError -> "You've got a runtime error!"
   ArithmeticError -> "You've got a Argument error!"
end

IO.puts(err)

Wenn das obige Programm ausgeführt wird, wird das folgende Ergebnis angezeigt:

You've got a Argument error!

NOTE- Die meisten Funktionen in der Elixir-Standardbibliothek werden zweimal implementiert, wobei einmal Tupel zurückgegeben werden und das andere Mal Fehler auftreten. Zum Beispiel dieFile.read und die File.read!Funktionen. Das erste hat ein Tupel zurückgegeben, wenn die Datei erfolgreich gelesen wurde und ein Fehler aufgetreten ist. Dieses Tupel wurde verwendet, um den Grund für den Fehler anzugeben. Der zweite hat einen Fehler ausgelöst, wenn ein Fehler aufgetreten ist.

Wenn wir den ersten Funktionsansatz verwenden, müssen wir case für die Musterübereinstimmung mit dem Fehler verwenden und entsprechend handeln. Im zweiten Fall verwenden wir den Try-Rescue-Ansatz für fehleranfälligen Code und behandeln Fehler entsprechend.

Würfe

In Elixir kann ein Wert geworfen und später abgefangen werden. Wurf und Fang sind für Situationen reserviert, in denen es nicht möglich ist, einen Wert abzurufen, es sei denn, Sie verwenden Wurf und Fang.

Die Instanzen sind in der Praxis eher ungewöhnlich, außer wenn sie mit Bibliotheken verbunden sind. Nehmen wir nun zum Beispiel an, dass das Enum-Modul keine API zum Suchen eines Werts bereitgestellt hat und dass wir das erste Vielfache von 13 in einer Liste von Zahlen finden mussten -

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)

Wenn das obige Programm ausgeführt wird, wird das folgende Ergebnis erzeugt:

Got 26

Ausgang

Wenn ein Prozess an „natürlichen Ursachen“ stirbt (z. B. nicht behandelte Ausnahmen), sendet er ein Ausgangssignal. Ein Prozess kann auch durch explizites Senden eines Ausgangssignals sterben. Betrachten wir das folgende Beispiel:

spawn_link fn -> exit(1) end

Im obigen Beispiel wurde der verknüpfte Prozess durch Senden eines Exit-Signals mit dem Wert 1 beendet. Beachten Sie, dass der Exit auch mit try / catch „abgefangen“ werden kann. Zum Beispiel -

val = try do
   exit "I am exiting"
catch
   :exit, _ -> "not really"
end

IO.puts(val)

Wenn das obige Programm ausgeführt wird, wird das folgende Ergebnis erzeugt:

not really

Nach

Manchmal muss sichergestellt werden, dass eine Ressource nach einer Aktion bereinigt wird, die möglicherweise einen Fehler auslösen kann. Mit dem try / after-Konstrukt können Sie dies tun. Zum Beispiel können wir eine Datei öffnen und sie mit einer after-Klausel schließen - auch wenn etwas schief geht.

{:ok, file} = File.open "sample", [:utf8, :write]
try do
   IO.write file, "olá"
   raise "oops, something went wrong"
after
   File.close(file)
end

Wenn wir dieses Programm ausführen, wird es uns einen Fehler geben. Aber dieafter Die Anweisung stellt sicher, dass der Dateideskriptor bei einem solchen Ereignis geschlossen wird.