Tutti gli errori in Elixir implementano l'Exception Behaviour. Proprio come l'Access Behaviour, l'Exception Behaviour definisce delle funzioni di callback che un modulo deve implementare per rispettare il contratto software del behaviour. Una volta che un errore è definito, ha le seguenti proprietà:
:message.raise/1 e raise/2 per sollevare l'errore desiderato.L'Exception Behaviour specifica anche due callback: message/1 e exception/1. Se non vengono implementate, verranno usate le implementazioni predefinite. message/1 trasforma la struct di errore in un messaggio leggibile quando viene chiamata con raise. exception/1 permette di aggiungere contesto al messaggio quando viene chiamata con raise/2.
Per definire un'eccezione a partire da un modulo di errore, usiamo la macro 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
Gli errori definiti possono essere usati come un errore integrato, usando raise/1 o raise/2.
raise/1 solleva un errore specifico tramite il nome del suo modulo oppure, se l'argomento è una stringa, solleva un RuntimeError con la stringa come messaggio.raise/2 solleva un errore specifico tramite il nome del suo modulo e accetta un argomento di attributi che viene usato per ottenere l'errore con il messaggio appropriato.Mentre continui a lavorare presso Instruments of Texas, si stanno facendo progressi sull'implementazione in Elixir della calcolatrice RPN. Il tuo team vorrebbe poter sollevare errori più specifici di quelli generici forniti dalla libreria standard. Stai facendo qualche ricerca, ma hai deciso di implementare due nuovi errori che seguono l'Exception Behaviour.
Dividere un numero per zero produce un risultato indefinito: il team ha deciso che è meglio rappresentarlo con un errore.
Implementa il modulo DivisionByZeroError in modo che abbia il messaggio di errore: "division by zero occurred"
raise DivisionByZeroError
# => ** (DivisionByZeroError) division by zero occurred
Le calcolatrici RPN usano uno stack per tenere traccia dei numeri prima che vengano utilizzati nei calcoli. Il team rappresenta questo stack con un array di numeri (interi e in virgola mobile), ad esempio: [3, 4.0]. Ogni operazione richiede una quantità precisa di numeri sullo stack per poter eseguire il proprio calcolo. Quando sullo stack non ci sono abbastanza numeri, si parla di errore di stack underflow. Implementa l'eccezione StackUnderflowError, che fornisce un messaggio predefinito e un contesto aggiuntivo opzionale
raise StackUnderflowError
# => ** (StackUnderflowError) stack underflow occurred
raise StackUnderflowError, "when dividing"
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing
Implementa la funzione divide/1, che prende uno stack (un array di due numeri) e:
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
Nota che l'ordine dell'array è invertito!
Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.