Cairo ofrece técnicas de gestión de errores para resolver problemas y controlar los errores, lo que permite que el código se ejecute sin problemas durante la ejecución.
En Cairo hay dos tipos de errores:
panic: estos errores terminan el programa de inmediato.Result: estos errores se pueden controlar durante la ejecución.panic
En Cairo, pueden surgir problemas inesperados durante la ejecución del programa, lo que da lugar a errores en tiempo de ejecución llamados «panic».
Esto detiene la ejecución del programa, lo cual resulta útil cuando continuar no tendría ningún sentido.
Un panic puede producirse de forma involuntaria, mediante acciones que provocan un panic en el código (por ejemplo, acceder a un array más allá de sus límites), o de forma deliberada, invocando la función panic.
fn main() {
let data = array![1, 2];
if true {
panic(data);
}
println!("This line will not be reached.");
}
Si ejecutas este ejemplo, se imprimiría lo siguiente en la consola:
Run panicked with [1, 2, ].
También existe una macro especial, llamada panic!, que permite usar un ByteArray como mensaje de error.
panic!("The error for the panic! Error message is not limited to 31 characters anymore");
assert!
La macro assert! es una herramienta útil para asegurar que se cumplen condiciones específicas en tu código.
Si la condición de assert! se evalúa como false, el programa provocará un panic con un mensaje de error de tipo ByteArray.
A menudo se usa para verificar suposiciones durante el desarrollo y asegurar que los valores cumplen ciertos criterios.
Por ejemplo:
fn main() {
let x = 5;
assert!(x > 0, "x must be greater than zero");
}
Si x no es mayor que cero, el programa provocará un panic con el mensaje "x must be greater than zero".
assert! resulta útil para comprobar invariantes y precondiciones sin escribir manualmente código de gestión de errores.
nopanic
La notación nopanic de Cairo indica que una función nunca provocará un panic.
fn function_never_panic() -> felt252 nopanic {
108
}
Una función nopanic solo se puede llamar desde una función que también esté anotada como nopanic.
panic_with
El atributo panic_with de Cairo sirve para marcar una función que devuelve un Option o un Result, y crea un envoltorio para la función anotada que provocará un panic si la función devuelve Option::None o 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
La enumeración Result gestiona los errores con elegancia, ya que proporciona información en lugar de provocar un fallo o un comportamiento indefinido.
enum Result<T, E> {
Ok: T,
Err: E,
}
Veamos un ejemplo de cómo podríamos usar esta enumeración para gestionar una división entre cero:
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),
}
}
?
El operador ? se usa para una gestión de errores concisa e implícita, y permite que la función que hace la llamada se encargue de los errores que puedan producirse.
Cuando usas el operador ? con un tipo Result o Option, hace lo siguiente:
Result::Ok(x) o Option::Some(x), devuelve directamente el valor interno x.Result::Err(e) o Option::None, propaga el error o None saliendo inmediatamente de la función.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),
}
}