Cairo bietet Techniken zur Fehlerbehandlung, mit denen du Probleme angehst und Fehler verwaltest, damit der Code während der Ausführung reibungslos läuft.
In Cairo gibt es zwei Arten von Fehlern:
panic: Diese Fehler beenden das Programm sofort.Result: Diese Fehler kannst du während der Laufzeit behandeln.panic
In Cairo können während der Programmausführung unerwartete Probleme auftreten, die zu Laufzeitfehlern führen, den sogenannten „Panics“.
Das stoppt die Programmausführung, was hilfreich ist, wenn eine Fortsetzung keinen Sinn ergeben würde.
Ein Panic kann entweder unbeabsichtigt auftreten, durch Aktionen, die den Code zum Panic bringen (z. B. der Zugriff auf ein Array außerhalb seiner Grenzen), oder absichtlich, indem du die Funktion panic aufrufst.
fn main() {
let data = array![1, 2];
if true {
panic(data);
}
println!("This line will not be reached.");
}
Wenn du dieses Beispiel ausführst, wird Folgendes in der Konsole ausgegeben:
Run panicked with [1, 2, ].
Es gibt außerdem ein spezielles Makro namens panic!, mit dem ein ByteArray als Fehlermeldung verwendet werden kann.
panic!("The error for the panic! Error message is not limited to 31 characters anymore");
assert!-MakroDas Makro assert! ist ein nützliches Werkzeug, um bestimmte Bedingungen in deinem Code durchzusetzen.
Wenn die Bedingung in assert! false ergibt, löst das Programm einen Panic mit einer ByteArray-Fehlermeldung aus.
Das wird oft verwendet, um Annahmen während der Entwicklung zu überprüfen und sicherzustellen, dass Werte bestimmte Kriterien erfüllen.
Zum Beispiel:
fn main() {
let x = 5;
assert!(x > 0, "x must be greater than zero");
}
Wenn x nicht größer als null ist, löst das Programm einen Panic mit der Meldung "x must be greater than zero" aus.
assert! ist hilfreich, um Invarianten und Vorbedingungen zu prüfen, ohne manuell Fehlerbehandlungscode zu schreiben.
nopanic-NotationDie nopanic-Notation in Cairo zeigt an, dass eine Funktion niemals einen Panic auslöst.
fn function_never_panic() -> felt252 nopanic {
108
}
Eine nopanic-Funktion kann nur in einer Funktion aufgerufen werden, die ebenfalls als nopanic gekennzeichnet ist.
panic_with-AttributDas panic_with-Attribut in Cairo markiert eine Funktion, die ein Option oder Result zurückgibt, und erstellt einen Wrapper für deine gekennzeichnete Funktion, der einen Panic auslöst, wenn die Funktion Option::None oder Result::Err zurückgibt.
#[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
Das Enum Result behandelt Fehler auf elegante Weise und gibt Feedback, statt abzustürzen oder undefiniertes Verhalten zu erzeugen.
enum Result<T, E> {
Ok: T,
Err: E,
}
Schauen wir uns ein Beispiel an, wie wir dieses Enum verwenden können, um eine Division durch null zu behandeln:
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),
}
}
?-OperatorDer ?-Operator wird für eine prägnante und implizite Fehlerbehandlung verwendet und überlässt der aufrufenden Funktion den Umgang mit allen Fehlern, die auftreten könnten.
Wenn du den ?-Operator auf einen Typ Result oder Option anwendest, macht er Folgendes:
Result::Ok(x) oder Option::Some(x) ist, gibt er den inneren Wert x direkt zurück.Result::Err(e) oder Option::None ist, gibt er den Fehler oder None weiter, indem er sofort aus der Funktion zurückkehrt.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),
}
}