Problema al usar el operador '?'' en función personalizada en Rust

Publicado por Brisa
hace 11 meses

Hola, soy nueva en Rust y estoy tratando de comprender el operador '?' para manejar errores de una manera más concisa. Sin embargo, estoy teniendo problemas para utilizar este operador en una función personalizada.

Aquí está el código que estoy intentando ejecutar:

use std::error::Error;

fn divide(a: i32, b: i32) -> Result<i32, Box<dyn Error>> {
    if b == 0 {
        Err("No se puede dividir entre cero")?;
    }
    Ok(a / b)
}

fn main() {
    let result = divide(10, 0);
    match result {
        Ok(value) => println!("El resultado es: {}", value),
        Err(error) => println!("Ocurrió un error: {}", error),
    }
}

Al compilar este código, obtengo el siguiente error:

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
 --> src/main.rs:6:22
  |
6 |         Err("No se puede dividir entre cero")?;
  |                      ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `std::result::Result<i32, std::boxed::Box<(dyn std::error::Error + 'static)>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error

¿Qué estoy haciendo mal en mi código? ¿Cómo puedo utilizar el operador '?' en esta función personalizada correctamente? Agradezco cualquier ayuda que me puedan brindar. ¡Gracias!

Rust operador ? función personalizada
Respuesta de Gordon Shumway
hace 11 meses

¡Hola Brisa! Veo que te estás metiendo con Rust y su gestión de errores,

El problema que tienes aquí es que estás intentando usar el operador ? con un valor de error que no es del tipo que tu función promete devolver. Quieres devolver un tipo Box<dyn Error>, pero estás pasando una cadena de texto al operador ?. Además, ese error no está siendo "empaquetado" en un Box. Para arreglar tu código, necesitas convertir ese mensaje de error en un tipo que implemente la interfaz Error. Una forma común de hacerlo es usar la estructura Box<dyn Error> con la conversión de String a Error usando Into::into() así:

use std::error::Error;

fn divide(a: i32, b: i32) -> Result<i32, Box<dyn Error>> {
    if b == 0 {
        // Aquí convertimos la cadena a un Error
        return Err("No se puede dividir entre cero".into());
    }
    Ok(a / b)
}

fn main() {
    let result = divide(10, 0);
    match result {
        Ok(value) => println!("El resultado es: {}", value),
        Err(error) => println!("Ocurrió un error: {}", error),
    }
}

Explicación rápida:

  • Cambié Err("No se puede dividir entre cero")?; por return Err("No se puede dividir entre cero".into());. Esto crea un nuevo Box<dyn Error> que es lo que se espera que la función retorne en caso de error. El método .into() convierte la cadena literal en un tipo Box<dyn Error>.
  • Notarás que puse return. Esto se debe a que queremos salir de la función inmediatamente después de encontrar el error, y el operador ? no es necesario porque ya estamos manejando el error de forma explícita.

Ahora el error está siendo manejado correctamente y tu función debería compilar sin problemas. ¡Espero que eso resuelva tu duda!