Tracks
/
Cairo
Cairo
/
Temario
/
Gestión de errores
Ge

Gestión de errores en Cairo

1 ejercicio

Acerca de Gestión de errores

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:

  • Errores irrecuperables con panic: estos errores terminan el programa de inmediato.
  • Errores recuperables con Result: estos errores se pueden controlar durante la ejecución.

Errores irrecuperables con 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");

La macro 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.

La notación 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.

El atributo 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'
}

Errores recuperables con 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 ?

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:

  • Si el valor es Result::Ok(x) o Option::Some(x), devuelve directamente el valor interno x.
  • Si el valor es 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),
    }
}
Editar en GitHub El enlace se abre en una nueva ventana o pestaña

Aprende Gestión de errores

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Gestión de errores