Elixir - 錯誤處理



Elixir 有三種錯誤處理機制:錯誤、丟擲和退出。讓我們詳細探討每種機制。

錯誤

錯誤(或異常)用於程式碼中發生異常情況時。可以透過嘗試將數字新增到字串中來獲取一個示例錯誤:

IO.puts(1 + "Hello")

執行以上程式時,會產生以下錯誤:

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

這是一個內建錯誤示例。

引發錯誤

我們可以使用 `raise` 函式引發錯誤。讓我們考慮一個例子來理解這一點:

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

其他錯誤可以透過 `raise/2` 傳遞錯誤名稱和關鍵字引數列表來引發。

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

您還可以定義自己的錯誤並引發它們。請考慮以下示例:

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

捕獲錯誤

我們不希望程式突然退出,而是需要仔細處理錯誤。為此,我們使用錯誤處理。我們使用`try/rescue`結構捕獲錯誤。讓我們考慮以下示例來理解這一點:

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

IO.puts(err.message)

執行以上程式時,會產生以下結果:

oops

我們在 `rescue` 語句中使用模式匹配處理了錯誤。如果我們沒有使用錯誤,只是想將其用於識別目的,我們也可以使用以下形式:

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

IO.puts(err)

執行以上程式時,會產生以下結果:

You've got a Argument error!

注意 - Elixir 標準庫中的大多數函式都實現了兩種方式,一種返回元組,另一種引發錯誤。例如,`File.read` 和 `File.read!` 函式。如果檔案讀取成功,第一個函式將返回一個元組;如果遇到錯誤,則使用此元組來提供錯誤原因。第二個函式如果遇到錯誤則引發錯誤。

如果我們使用第一種函式方法,則需要使用 `case` 來匹配錯誤模式並根據該模式採取行動。在第二種情況下,我們對容易出錯的程式碼使用 `try rescue` 方法並相應地處理錯誤。

丟擲

在 Elixir 中,可以丟擲一個值,然後稍後捕獲它。`throw` 和 `catch` 保留用於無法檢索值的情況,除非使用 `throw` 和 `catch`。

除了與庫互動時,這些情況在實踐中很少見。例如,現在假設 `Enum` 模組沒有提供任何查詢值的 API,並且我們需要在數字列表中找到第一個 13 的倍數:

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)

執行以上程式時,會產生以下結果:

Got 26

退出

當程序因“自然原因”(例如未處理的異常)死亡時,它會發送一個退出訊號。程序也可以透過顯式傳送退出訊號來死亡。讓我們考慮以下示例:

spawn_link fn -> exit(1) end

在上面的示例中,連結的程序透過傳送值為 1 的退出訊號死亡。請注意,`exit` 也可以使用 `try/catch` “捕獲”。例如:

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

IO.puts(val)

執行以上程式時,會產生以下結果:

not really

之後

有時需要確保在可能引發錯誤的一些操作後清理資源。`try/after` 結構允許您執行此操作。例如,我們可以開啟一個檔案並使用 `after` 子句關閉它,即使出現問題。

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

當我們執行此程式時,它會給我們一個錯誤。但是 `after` 語句將確保在任何此類事件發生時關閉檔案描述符。

廣告

© . All rights reserved.