Tracks
/
Cairo
Cairo
/
Temario
/
Manejo de errores
Ma

Manejo de errores en Cairo

1 ejercicio

Acerca de Manejo de errores

Cairo ofrece técnicas de manejo de errores para resolver problemas y gestionar los errores, lo que permite que el código se ejecute sin problemas durante su 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 manejar 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 «panics». Esto detiene la ejecución del programa, lo cual es útil cuando continuar no tendría ningún sentido. Un panic puede ocurrir de forma accidental, por acciones que hacen que el código entre en panic (por ejemplo, acceder a un array más allá de sus límites), o de forma deliberada, llamando a 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 hacer cumplir condiciones específicas en tu código. Si la condición en assert! se evalúa como false, el programa entrará en panic con un mensaje de error de tipo ByteArray. A menudo se usa para verificar suposiciones durante el desarrollo y asegurar que los valores cumplan 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 entrará en panic con el mensaje "x must be greater than zero". assert! es útil para comprobar invariantes y precondiciones sin escribir manualmente código de manejo de errores.

La notación nopanic

La notación nopanic de Cairo indica que una función nunca entrará en panic.

fn function_never_panic() -> felt252 nopanic {
    108
}

A una función nopanic solo se la 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 tu función anotada que entrará en 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 de forma controlada, ofreciendo información en lugar de fallar o producir un comportamiento indefinido.

enum Result<T, E> {
    Ok: T,
    Err: E,
}

Veamos un ejemplo de cómo podríamos usar esta enumeración para manejar una división por 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 un manejo de errores conciso e implícito, y deja que la función que llama se encargue de cualquier error que pueda ocurrir. Cuando usas el operador ? en un tipo Result u Option, hace lo siguiente:

  • Si el valor es Result::Ok(x) u Option::Some(x), devuelve directamente el valor interno x.
  • Si el valor es Result::Err(e) u Option::None, propaga el error o None regresando de inmediato desde 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 ventana o pestaña nueva

Aprende Manejo de errores

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Manejo de errores