Erlang - 異常



異常處理在任何程式語言中都是必需的,用於處理執行時錯誤,以便維護應用程式的正常流程。異常通常會中斷應用程式的正常流程,這就是為什麼我們需要在應用程式中使用異常處理的原因。

通常,當 Erlang 中發生異常或錯誤時,將顯示以下訊息。

{"init terminating in do_boot", {undef,[{helloworld,start,[],[]}, 
{init,start_it,1,[]},{init,start_em,1,[]}]}}

崩潰轉儲將寫入 -

erl_crash.dump
init terminating in do_boot ()

在 Erlang 中,有三種類型的異常 -

  • 錯誤 - 呼叫 erlang:error(Reason) 將終止當前程序中的執行,並在您捕獲它時包含最後呼叫的函式及其引數的堆疊跟蹤。這些是導致上面執行時錯誤的異常型別。

  • 退出 - 有兩種型別的退出:'內部'退出和'外部'退出。內部退出是透過呼叫函式 exit/1 觸發的,並使當前程序停止執行。外部退出使用 exit/2 呼叫,並且與 Erlang 併發方面的多個程序有關。

  • 丟擲 - 丟擲是一類異常,用於程式設計師可以預期處理的情況。與退出和錯誤相比,它們並沒有真正帶有任何“崩潰該程序!”的意圖,而是控制流程。當您在預期程式設計師處理丟擲時使用它們時,通常最好使用它們記錄模組中的用法。

try ... catch 是一種評估表示式的 方法,同時允許您處理成功的情況以及遇到的錯誤。

try catch 表示式的通用語法如下。

語法

try Expression of 
SuccessfulPattern1 [Guards] -> 
Expression1; 
SuccessfulPattern2 [Guards] -> 
Expression2 

catch 
TypeOfError:ExceptionPattern1 -> 
Expression3; 
TypeOfError:ExceptionPattern2 -> 
Expression4 
end

try 和 of 之間的表示式被稱為受保護的。這意味著在該呼叫中發生的任何型別的異常都將被捕獲。try ... of 和 catch 之間的模式和表示式與 case ... of 的行為完全相同。

最後,是 catch 部分 - 在這裡,您可以將 TypeOfError 替換為 error、throw 或 exit,分別對應我們本章中看到的每種型別。如果未提供型別,則假定為 throw。

以下是 Erlang 中的一些錯誤和錯誤原因 -

錯誤 錯誤型別
badarg 錯誤的引數。引數的資料型別錯誤,或者格式錯誤。
badarith 算術表示式中的錯誤引數。
{badmatch,V} 匹配表示式的評估失敗。值 V 沒有匹配。
function_clause 在評估函式呼叫時找不到匹配的函式子句。
{case_clause,V} 在評估 case 表示式時找不到匹配的分支。值 V 沒有匹配。
if_clause 在評估 if 表示式時找不到 true 分支。
{try_clause,V} 在評估 try 表示式的 of 部分時找不到匹配的分支。值 V 沒有匹配。
undef 在評估函式呼叫時找不到函式。
{badfun,F} 函式 F 有問題
{badarity,F} 函式應用於錯誤數量的引數。F 描述了函式和引數。
timeout_value receive..after 表示式中的超時值計算結果不是整數或無限大。
noproc 嘗試連結到不存在的程序。

下面是一個關於如何使用這些異常以及如何執行操作的示例。

  • 第一個函式生成所有可能的異常型別。

  • 然後我們編寫一個包裝器函式,在 try...catch 表示式中呼叫 generate_exception

示例

-module(helloworld). 
-compile(export_all). 

generate_exception(1) -> a; 
generate_exception(2) -> throw(a); 
generate_exception(3) -> exit(a); 
generate_exception(4) -> {'EXIT', a}; 
generate_exception(5) -> erlang:error(a). 

demo1() -> 
   [catcher(I) || I <- [1,2,3,4,5]]. 
catcher(N) -> 
   try generate_exception(N) of 
      Val -> {N, normal, Val} 
   catch 
      throw:X -> {N, caught, thrown, X}; 
      exit:X -> {N, caught, exited, X}; 
      error:X -> {N, caught, error, X} 
   end. 
      
demo2() -> 
   [{I, (catch generate_exception(I))} || I <- [1,2,3,4,5]]. 
demo3() -> 
   try generate_exception(5) 
   catch 
      error:X -> 
         {X, erlang:get_stacktrace()} 
   end. 
   
lookup(N) -> 
   case(N) of 
      1 -> {'EXIT', a}; 
      2 -> exit(a) 
   end.

如果我們像 helloworld:demo() 那樣執行程式,我們將得到以下輸出 -

輸出

[{1,normal,a},
{2,caught,thrown,a},
{3,caught,exited,a},
{4,normal,{'EXIT',a}},
{5,caught,error,a}]
廣告