Tr

Try/Rescue 在 Elixir

1 個練習

關於 Try/Rescue

try .. rescue可以用來捕捉並評估區塊內引發的錯誤。

例如:

try do
  raise RuntimeError, "error"
rescue
  e in RuntimeError -> :error
end
  • 第 1 行,區塊以try宣告。
  • 第 2 行,可能產生錯誤的函式呼叫放在這裡,在這個例子中我們呼叫的是raise/1。
  • 第 4 行,在rescue區段中,我們對引發錯誤的_模組_名稱進行模式比對
    • 在->的左側:
      • e會比對到錯誤結構。
      • in是關鍵字。
      • RuntimeError是要比對的模組,但也可以比對任何錯誤模組,或使用_比對所有錯誤。
    • 在右側:
      • 錯誤符合時要執行的指示。

錯誤結構

你用這種方式 rescue 的錯誤(有時也稱為「例外」)都是結構。 不同的錯誤結構有不同的鍵。 在標準函式庫的「例外」一節中,可以找到所有預先定義錯誤的清單。

# ArithmeticError caused by division by zero
%ArithmeticError{message: "bad argument in arithmetic expression"}

# Protocol.UndefinedError caused by passing `nil` to `Enum.count/1`
%Protocol.UndefinedError{description: "", protocol: Enumerable, value: nil}

在 Elixir 中 rescue 錯誤的情況非常少見。 通常被 rescue 的錯誤會被記錄下來,或送到外部的監控服務,然後再重新引發。 這表示我們通常不太在意特定錯誤結構內部的組成。

例外概念說明了如何定義自訂的錯誤結構。

避免反面模式

  • 避免使用錯誤來控制邏輯流程的程式設計模式。這在 Elixir 中是反面模式。

    # Avoid using errors for control-flow.
    try do
      {:ok, value} = MyModule.janky_function()
      "All good! #{value}."
    rescue
      e in RuntimeError ->
        reason = e.message
        "Uh oh! #{reason}."
    end
    
    # Rather, use control-flow structures for control-flow.
    case MyModule.janky_function() do
      {:ok, value} -> "All good! #{value}."
      {:error, reason} -> "Uh oh! #{reason}."
    end
    

該引發,還是不該引發,這就是問題所在

正如Elixir 入門指南所述:

在[執行某個動作]時發生的錯誤算不算例外,取決於你的應用程式。這就是為什麼 Elixir 不會強制 [...] 函式採用例外。它反而讓開發者自行選擇最合適的做法。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 Try/Rescue