Elixir 中的所有錯誤都實作了_例外行為_。就像_存取行為_一樣,_例外行為_定義了模組必須實作的幾個回呼函式,以滿足這個行為的軟體契約。一旦定義了錯誤,它就具備下列特性:
:message欄位。raise/1與raise/2搭配使用,來拋出預期的錯誤_例外行為_也指定了兩個回呼函式:message/1 和 exception/1。如果沒有實作,就會使用預設的實作。當搭配raise呼叫時,message/1會把錯誤結構轉換成可讀的訊息。當搭配raise/2呼叫時,exception/1允許在訊息中加入額外的脈絡資訊。
若要從錯誤模組定義例外,我們會使用defexception巨集:
# Defines a minimal error, with the name `MyError`
defmodule MyError do
defexception message: "error"
end
# Defines an error with a customized exception/1 function
defmodule MyCustomizedError do
defexception message: "custom error"
@impl true
def exception(value) do
case value do
[] ->
%MyCustomizedError{}
_ ->
%MyCustomizedError{message: "Alert: " <> value}
end
end
end
定義好的錯誤可以像內建錯誤一樣,透過raise/1或raise/2來使用。
raise/1會依照模組名稱拋出特定的錯誤;或者,如果引數是字串,就會拋出一個RuntimeError,並以該字串做為訊息。raise/2會依照模組名稱拋出特定的錯誤,並接受一個屬性引數,用來取得帶有適當訊息的錯誤。在你繼續於 Instruments of Texas 工作的同時,RPN 計算機的 Elixir 實作也有了進展。你的團隊希望能引發比標準函式庫提供的通用錯誤更具體的錯誤。你正在做一些研究,但已經決定要實作兩個新的錯誤,這兩個錯誤會實作 Exception Behaviour。
將一個數字除以零會產生未定義的結果,團隊認為用錯誤來表示最為合適。
實作DivisionByZeroError模組,讓它的錯誤訊息為:"division by zero occurred"
raise DivisionByZeroError
# => ** (DivisionByZeroError) division by zero occurred
RPN 計算機使用_堆疊_來追蹤尚未相加的數字。團隊用數字(整數和浮點數)的陣列來表示這個_堆疊_,例如:[3, 4.0]。每個運算需要在堆疊上有特定數量的數字,才能執行計算。當堆疊上的數字不夠時,就稱為堆疊下溢錯誤。實作StackUnderflowError例外,它提供一則預設訊息,以及可選的額外情境資訊。
raise StackUnderflowError
# => ** (StackUnderflowError) stack underflow occurred
raise StackUnderflowError, "when dividing"
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing
實作divide/1函式,它接收一個堆疊_(兩個數字組成的陣列)_,並且:
RPNCalculator.Exception.divide([])
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing
RPNCalculator.Exception.divide([0, 100])
# => ** (DivisionByZeroError) division by zero occurred
RPNCalculator.Exception.divide([4, 16])
# => 4
注意,陣列的順序是相反的!