Τα σφάλματα συμβαίνουν. Στην Elixir, ενώ οι άνθρωποι συχνά λένε "άφησέ το να κρασάρει", υπάρχουν στιγμές που χρειάζεται να διασώσουμε την κλήση της συνάρτησης σε μια γνωστή καλή κατάσταση για να εκπληρώσουμε ένα συμβόλαιο λογισμικού. Σε ορισμένες γλώσσες προγραμματισμού, τα σφάλματα χρησιμοποιούνται ως μέθοδος ροής ελέγχου, αλλά στην Elixir αυτό το μοτίβο αποθαρρύνεται. Συχνά μπορούμε να αναγνωρίσουμε συναρτήσεις που μπορεί να πετάξουν ένα σφάλμα μόνο από το όνομά τους: οι συναρτήσεις που πετούν σφάλματα έχουν ! στο τέλος του ονόματός τους. Αυτό συμβαίνει σε αντιδιαστολή με συναρτήσεις που επιστρέφουν {:ok, value} ή :error. Δες αυτά τα παραδείγματα από τη βιβλιοθήκη:
Map.fetch(%{a: 1}, :b)
# => :error
Map.fetch!(%{a: 1}, :b)
# => raises KeyError
Η Elixir παρέχει έναν μηχανισμό για να διασώζεσαι από σφάλματα χρησιμοποιώντας try .. rescue
try do
raise RuntimeError, "error"
rescue
e in RuntimeError -> :error
end
Ας εξετάσουμε αυτόν τον μηχανισμό:
try.raise/2.rescue, κάνουμε αντιστοίχιση προτύπων στο όνομα του Module του σφάλματος που πετάχτηκε
->:
e αντιστοιχίζεται στο struct του σφάλματος.in είναι λέξη-κλειδί.RuntimeError είναι το σφάλμα από το οποίο θέλουμε να διασωθούμε.
_ αντί για το όνομα του module ή να παραλείψουμε εντελώς τη λέξη-κλειδί in.Τα σφάλματα (που μερικές φορές αποκαλούνται και "εξαιρέσεις") από τα οποία διασώζεσαι με αυτόν τον τρόπο είναι structs. Η διάσωση από σφάλματα στην Elixir γίνεται πολύ σπάνια. Συνήθως το σφάλμα από το οποίο διασωθήκαμε καταγράφεται ή στέλνεται σε μια εξωτερική υπηρεσία παρακολούθησης και μετά πετιέται ξανά. Αυτό σημαίνει ότι συνήθως δε μας ενδιαφέρει η εσωτερική δομή του συγκεκριμένου struct σφάλματος.
Στην έννοια Exceptions θα μάθεις περισσότερα για τα structs σφάλματος, συμπεριλαμβανομένου του πώς να ορίσεις το δικό σου προσαρμοσμένο σφάλμα.
Ενώ εργάζεσαι στην Instruments of Texas, σου έχει ανατεθεί να δουλέψεις πάνω σε μια πειραματική αριθμομηχανή Αντίστροφης Πολωνικής Σημειογραφίας [RPN] γραμμένη σε Elixir. Η ομάδα σου αντιμετωπίζει ένα πρόβλημα: κάποιες πράξεις πετούν σφάλματα και κάνουν τη διαδικασία να καταρρεύσει. Σου έχει ανατεθεί να γράψεις μια συνάρτηση που περιτυλίγει τη συνάρτηση πράξης, ώστε τα σφάλματα να μπορούν να αντιμετωπιστούν πιο κομψά με ιδιωματικό κώδικα Elixir.
Υλοποίησε τη συνάρτηση calculate!/2 ώστε να καλεί τη συνάρτηση πράξης με τη στοίβα ως μοναδικό όρισμα. Η συνάρτηση πράξης ορίζεται κάπου αλλού, αλλά ξέρεις ότι μπορεί είτε να ολοκληρωθεί με επιτυχία είτε να πετάξει ένα σφάλμα.
stack = []
operation = fn _ -> :ok end
RPNCalculator.calculate!(stack, operation)
# => :ok
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate!(stack, operation)
# => ** (ArgumentError) An error occurred
Τα ονόματα συναρτήσεων που τελειώνουν σε
!προειδοποιούν τους προγραμματιστές ότι αυτή η συνάρτηση μπορεί να πετάξει ένα σφάλμα
Όταν κάνεις περισσότερη έρευνα, παρατηρείς ότι πολλές συναρτήσεις χρησιμοποιούν άτομα και πλειάδες για να δηλώσουν την επιτυχία ή την αποτυχία τους. Υλοποίησε τη calculate/2 χρησιμοποιώντας αυτή τη στρατηγική.
stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate(stack, operation)
# => {:ok, "operation completed"}
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate(stack, operation)
# => :error
Κάποια από τα σφάλματα περιέχουν σημαντικές πληροφορίες που οι συνάδελφοί σου πρέπει να έχουν για να διασφαλίσουν τη σωστή λειτουργία του συστήματος. Υλοποίησε τη calculate_verbose/2 για να μεταβιβάσεις το μήνυμα του σφάλματος. Το σφάλμα είναι ένα struct που έχει ένα πεδίο :message.
stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:ok, "operation completed"}
stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:error, "An error occurred"}
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Elixir με 58 έννοιες168 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.