İksir - Hataları Giderme

Elixir'in üç hata mekanizması vardır: hatalar, fırlatmalar ve çıkışlar. Her mekanizmayı ayrıntılı olarak inceleyelim.

Hata

Kodda istisnai şeyler olduğunda hatalar (veya istisnalar) kullanılır. Bir dizgeye bir sayı eklenmeye çalışılarak örnek bir hata alınabilir -

IO.puts(1 + "Hello")

Yukarıdaki program çalıştırıldığında, aşağıdaki hatayı üretir -

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

Bu dahili bir örnek hataydı.

Hata Oluşturma

Yapabiliriz raiseyükseltme işlevlerini kullanan hatalar. Aynısını anlamak için bir örnek ele alalım -

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

Yükseltme / 2 hata adı ve anahtar kelime argümanları listesi geçildiğinde başka hatalar ortaya çıkabilir.

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

Ayrıca kendi hatalarınızı tanımlayabilir ve bunları artırabilirsiniz. Şu örneği düşünün -

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

Hataları Kurtarmak

Programlarımızın aniden kapanmasını istemiyoruz, bunun yerine hataların dikkatlice ele alınması gerekiyor. Bunun için hata işlemeyi kullanıyoruz. Bizrescue kullanarak hatalar try/rescueinşa etmek. Aynısını anlamak için aşağıdaki örneği ele alalım -

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

IO.puts(err.message)

Yukarıdaki program çalıştırıldığında, aşağıdaki sonucu verir -

oops

Rescue ifadesindeki hataları örüntü eşleştirmeyi kullanarak ele aldık. Hatayı kullanmazsak ve sadece tanımlama amacıyla kullanmak istiyorsak, formu da kullanabiliriz -

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

IO.puts(err)

Yukarıdaki program çalıştırıldığında, aşağıdaki sonucu verir -

You've got a Argument error!

NOTE- Elixir standart kitaplığındaki çoğu işlev, bir kez tuple döndüren ve diğer zaman yükseltme hataları olmak üzere iki kez uygulanır. Örneğin,File.read ve File.read!fonksiyonlar. İlki, dosya başarılı bir şekilde okunduysa bir demet döndürdü ve bir hatayla karşılaşılırsa, bu demet hatanın nedenini belirtmek için kullanıldı. İkincisi, bir hatayla karşılaşıldığında bir hatayı ortaya çıkardı.

İlk fonksiyon yaklaşımını kullanırsak, hatayı örüntü eşleştirmek için durum kullanmalı ve buna göre işlem yapmalıyız. İkinci durumda, hataya meyilli kod için kurtarmayı dene yaklaşımını kullanıyoruz ve hataları buna göre ele alıyoruz.

Atar

İksir'de bir değer atılabilir ve daha sonra yakalanabilir. Fırlatma ve Yakalama, fırlatma ve yakalama kullanılmadıkça bir değer almanın mümkün olmadığı durumlar için ayrılmıştır.

Örnekler, kitaplıklarla arabirim oluşturma dışında pratikte oldukça nadirdir. Örneğin, şimdi Enum modülünün bir değer bulmak için herhangi bir API sağlamadığını ve bir sayılar listesinde 13'ün ilk katını bulmamız gerektiğini varsayalım -

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)

Yukarıdaki program çalıştırıldığında, aşağıdaki sonucu verir -

Got 26

çıkış

Bir süreç “doğal nedenlerden” öldüğünde (örneğin, işlenmemiş istisnalar), bir çıkış sinyali gönderir. Bir işlem ayrıca açıkça bir çıkış sinyali göndererek de ölebilir. Şu örneği ele alalım -

spawn_link fn -> exit(1) end

Yukarıdaki örnekte, bağlantılı süreç 1 değerinde bir çıkış sinyali göndererek öldü. Çıkışın dene / yakala kullanılarak da "yakalanabileceğini" unutmayın. Örneğin -

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

IO.puts(val)

Yukarıdaki program çalıştırıldığında, aşağıdaki sonucu verir -

not really

Sonra

Bazen, bir hataya yol açabilecek bazı işlemlerden sonra bir kaynağın temizlenmesini sağlamak gerekir. Try / after yapısı bunu yapmanıza izin verir. Örneğin, bir dosyayı açabilir ve bir şeyler ters gitse bile kapatmak için after cümlesini kullanabiliriz.

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

Bu programı çalıştırdığımızda bize bir hata verecektir. Fakatafter ifadesi, bu tür herhangi bir olayda dosya tanımlayıcısının kapatılmasını sağlayacaktır.