Spracovanie Chýb
Bežne môžeme vidieť pri funkciách návratovú hodnotu tuple {:error, reason}
, ale Elixir podporuje aj výnimky a v tejto lekcii si ukážeme ako spracovávať chyby a rôzne mechanizmy ktoré máme k dispozícii.
Vo všeobecnosti je v Elixire konvenciou vytvárať funkciu example/1
, ktorá vráti {:ok, result}
alebo {:error, reason}
a funkcia example!/1
, ktorá vráti neobalený výsledok alebo vyvolá chybu.
Táto lekcia sa zameriava na spracovanie týchto chýb
Spracovanie Chýb
Predtým, než môžeme spracovávať chyby potrebujeme ich vytvoriť a najjednoduchší spôsob ako to spraviť je pomocou raise/1
:
iex> raise "Oh no!"
** (RuntimeError) Oh no!
Ak chceme špecifikovať typ a správu musíme použiť raise/2
:
iex> raise ArgumentError, message: "the argument value is invalid"
** (ArgumentError) the argument value is invalid
Keď vieme, že môže nastať chyba, môžeme ju zachytiť pomocou try/rescue
a pattern matchingu:
iex> try do
...> raise "Oh no!"
...> rescue
...> e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
...> end
An error occurred: Oh no!
:ok
Je možné zachytiť viacero chýb v jednom bloku rescue:
try do
opts
|> Keyword.fetch!(:source_file)
|> File.read!()
rescue
e in KeyError -> IO.puts("missing :source_file option")
e in File.Error -> IO.puts("unable to read source file")
end
After
Niekedy môže byť nevyhnutné spustiť akciu po našom try/rescue
bloku bez ohľadu na to či nastala chyba. Na toto máme k dispozícii try/after
podobne ako v Ruby begin/rescue/ensure
alebo v Jave try/catch/finally
:
iex> try do
...> raise "Oh no!"
...> rescue
...> e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
...> after
...> IO.puts "The end!"
...> end
An error occurred: Oh no!
The end!
:ok
Bežne sa after používa pri práci so súbormi alebo pripojeniami, ktoré by mali byť zatvorené:
{:ok, file} = File.open("example.json")
try do
# Do hazardous work
after
File.close(file)
end
Nové Chyby
Aj keď Elixir má množstvo zabudovaných typov chýb ako napríklad RuntimeError
, ale máme možnosť vytvoriť si svoje typy chýb ak potrebujeme niečo veľmi špecifické. Vytváranie nových typov chýb je jednoduché s pomocou makra defexception/1
, ktoré akceptuje možnosť :message
, ktorá nastaví štandardnú chybovú správu:
defmodule ExampleError do
defexception message: "an example error has occurred"
end
A teraz si vyskúšajme náš nový typ chyby:
iex> try do
...> raise ExampleError
...> rescue
...> e in ExampleError -> e
...> end
%ExampleError{message: "an example error has occurred"}
Throws
Ďalší mechanizmus pre prácu s chybami v Elixire je throw
a catch
. V praxi sa vyskytujú veľmi zriedka v novšom Elixir kóde, ale aj napriek tomu je dôležité vedieť a chápať ako fungujú.
Funkcia throw/1
nám dáva možnosť ukončiť vykonávanie programu so špecifickou hodnotu, ktorú môžeme zachytiť (catch
) a použiť:
iex> try do
...> for x <- 0..10 do
...> if x == 5, do: throw(x)
...> IO.puts(x)
...> end
...> catch
...> x -> "Caught: #{x}"
...> end
0
1
2
3
4
"Caught: 5"
Ako sme spomenuli, throw/catch
sú zriedkavé a väčšinou existujú ako dočasné riešenie ak knižnice neposkytujú adekvátne API.
Exiting
Posledný mechanizmus na spracovanie chýb, ktorý nám Elixir poskytuje je exit
. Signál Exit sa vyskytne kedykoľvek zanikne proces a sú dôležitou časťou odolnosti voči chybám Elixiru.
Ak chceme explicitne ukončiť aplikáciu môžeme použiť exit/1
:
iex> spawn_link fn -> exit("oh no") end
** (EXIT from #PID<0.101.0>) "oh no"
Je možné zachytiť exit pomocou try/catch
, ale to sa deje len vo veľmi zriedkavých prípadoch. Skoro vo všetkých prípadoch je výhodné nechať supervisora, ktorý si poradí so zaniknutím procesu:
iex> try do
...> exit "oh no!"
...> catch
...> :exit, _ -> "exit blocked"
...> end
"exit blocked"
Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!