Η Cairo παρέχει τεχνικές διαχείρισης σφαλμάτων για την αντιμετώπιση προβλημάτων και τη διαχείριση σφαλμάτων, επιτρέποντας την ομαλή εκτέλεση του κώδικα.
Υπάρχουν δύο τύποι σφαλμάτων στην Cairo:
panic: αυτά τα σφάλματα τερματίζουν το πρόγραμμα αμέσως.Result: αυτά τα σφάλματα μπορούν να αντιμετωπιστούν κατά τη διάρκεια της εκτέλεσης.panic
Στην Cairo, κατά την εκτέλεση του προγράμματος μπορεί να προκύψουν απρόσμενα προβλήματα, που οδηγούν σε σφάλματα χρόνου εκτέλεσης, τα λεγόμενα "panics".
Αυτό σταματά την εκτέλεση του προγράμματος, κάτι που βοηθά στην περίπτωση όπου η συνέχεια δεν θα είχε κανένα νόημα.
Ένα panic μπορεί να συμβεί είτε άθελά μας, μέσα από ενέργειες που προκαλούν το panic του κώδικα (π.χ. η πρόσβαση σε έναν πίνακα πέρα από τα όρια του), είτε σκόπιμα, καλώντας τη συνάρτηση panic.
fn main() {
let data = array![1, 2];
if true {
panic(data);
}
println!("This line will not be reached.");
}
Η εκτέλεση αυτού του παραδείγματος θα εκτυπώσει τα εξής στην κονσόλα:
Run panicked with [1, 2, ].
Υπάρχει επίσης μια ειδική μακροεντολή, η panic!, που επιτρέπει να χρησιμοποιηθεί ένα ByteArray ως μήνυμα σφάλματος.
panic!("The error for the panic! Error message is not limited to 31 characters anymore");
assert!
Η μακροεντολή assert! είναι ένα χρήσιμο εργαλείο για να επιβάλλεις συγκεκριμένες συνθήκες στον κώδικά σου.
Αν η συνθήκη στο assert! αξιολογηθεί σε false, το πρόγραμμα θα προκαλέσει panic με ένα μήνυμα σφάλματος ByteArray.
Αυτό χρησιμοποιείται συχνά για να επαληθεύεις υποθέσεις κατά την ανάπτυξη και να διασφαλίζεις ότι οι τιμές πληρούν ορισμένα κριτήρια.
Για παράδειγμα:
fn main() {
let x = 5;
assert!(x > 0, "x must be greater than zero");
}
Αν το x δεν είναι μεγαλύτερο από το μηδέν, το πρόγραμμα θα προκαλέσει panic με το μήνυμα "x must be greater than zero".
Η assert! είναι χρήσιμη για τον έλεγχο αναλλοίωτων συνθηκών και προϋποθέσεων χωρίς να γράφεις χειροκίνητα κώδικα διαχείρισης σφαλμάτων.
nopanic
Ο συμβολισμός nopanic της Cairo δηλώνει ότι μια συνάρτηση δεν θα προκαλέσει ποτέ panic.
fn function_never_panic() -> felt252 nopanic {
108
}
Μια συνάρτηση nopanic μπορεί να κληθεί μόνο μέσα από μια συνάρτηση που είναι επίσης επισημασμένη ως nopanic.
panic_with
Το χαρακτηριστικό panic_with της Cairo χρησιμοποιείται για να επισημάνει μια συνάρτηση που επιστρέφει Option ή Result, και δημιουργεί ένα περιτύλιγμα για τη συνάρτηση που έχεις επισημάνει, το οποίο θα προκαλέσει panic αν η συνάρτηση επιστρέψει Option::None ή Result::Err.
#[panic_with('value is 0', wrap_not_zero)]
fn check_not_zero(value: u128) -> Option<u128> {
if value == 0 {
Option::None
} else {
Option::Some(value)
}
}
fn main() {
check_not_zero(0); // -> returns Option::None
wrap_not_zero(0); // -> panics with 'value is 0'
}
Result
Το enum Result χειρίζεται τα σφάλματα με κομψό τρόπο, παρέχοντας ανατροφοδότηση αντί να καταρρέει ή να παράγει απροσδιόριστη συμπεριφορά.
enum Result<T, E> {
Ok: T,
Err: E,
}
Ας δούμε ένα παράδειγμα για το πώς θα μπορούσαμε να χρησιμοποιήσουμε αυτό το enum για να χειριστούμε μια διαίρεση με το μηδέν:
fn divide(a: u32, b: u32) -> Result<u32, ByteArray> {
if b == 0 {
return Result::Err("Error: Division by zero"); // Return an error if division by zero is attempted
}
Result::Ok(a / b)
}
fn main() {
// Test with division by zero
match divide(10, 0) {
Result::Ok(result) => println!("Division successful: {}", result),
Result::Err(e) => println!("{}", e),
}
}
?
Ο τελεστής ? χρησιμοποιείται για συνοπτική και έμμεση διαχείριση σφαλμάτων, αφήνοντας τη συνάρτηση που καλεί να αντιμετωπίσει τυχόν σφάλματα που μπορεί να προκύψουν.
Όταν χρησιμοποιείς τον τελεστή ? σε έναν τύπο Result ή Option, κάνει τα εξής:
Result::Ok(x) ή Option::Some(x), επιστρέφει απευθείας την εσωτερική τιμή x.Result::Err(e) ή Option::None, διαδίδει το σφάλμα ή το None επιστρέφοντας αμέσως από τη συνάρτηση.fn parse_u8(s: felt252) -> Result<u8, felt252> {
match s.try_into() {
Option::Some(value) => Result::Ok(value),
Option::None => Result::Err('Invalid integer'),
}
}
fn do_something_with_parse_u8(input: felt252) -> Result<u8, felt252> {
let input_to_u8: u8 = parse_u8(input)?;
// DO SOMETHING
let res = input_to_u8 - 1;
Result::Ok(res)
}
fn main() {
let number: felt252 = 258;
match do_something_with_parse_u8(number) {
Result::Ok(value) => println!("Result: {}", value),
Result::Err(e) => println!("Error: {}", e),
}
}