not found error error-handling rust

error-handling - error - 404 not found apache



¿Cómo se definen los tipos de ''Error'' personalizados en Rust? (3)

¿Es esa la forma más idiomática de hacerlo? ¿Y cómo implemento el rasgo de error?

Es una forma común, sí. "idiomático" depende de la fuerza con la que se escriban los errores y de cómo interactúa con otras cosas.

¿Y cómo implemento el rasgo de error?

Hablando estrictamente, no necesitas hacerlo aquí. Es posible que para la interoperabilidad con otras cosas que requieren un Error , pero como ha definido su tipo de devolución como esta enumeración directamente, su código debería funcionar sin él.

Estoy escribiendo una función que podría devolver varios de varios errores diferentes.

fn foo(...) -> Result<..., MyError> {}

Probablemente necesitaré definir mi propio tipo de error para representar tales errores. Supongo que sería una enum de posibles errores, con algunas de las variantes de enum que tienen datos de diagnóstico adjuntos:

enum MyError { GizmoError, WidgetNotFoundError(widget_name: String) }

¿Es esa la forma más idiomática de hacerlo? ¿Y cómo implemento el rasgo de Error ?


Implementas el Error exactamente como lo harías con cualquier otro rasgo ; no hay nada extremadamente especial al respecto

pub trait Error: Debug + Display { fn description(&self) -> &str { /* ... */ } fn cause(&self) -> Option<&Error> { /* ... */ } fn source(&self) -> Option<&(Error + ''static)> { /* ... */ } }

description , la cause y la source tienen implementaciones predeterminadas 1 , y su tipo también debe implementar Debug y Display , ya que son supertraits.

use std::{error::Error, fmt}; #[derive(Debug)] struct Thing; impl Error for Thing {} impl fmt::Display for Thing { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Oh no, something bad went down") } }

Por supuesto, lo que contiene Thing y, por lo tanto, las implementaciones de los métodos, depende en gran medida del tipo de errores que desee cometer. Quizás desee incluir un nombre de archivo allí, o tal vez un número entero de algún tipo. Quizás desee tener una enum lugar de una struct para representar varios tipos de errores.

Si terminas envolviendo los errores existentes, entonces recomendaría implementar From para convertir entre esos errores y tu error. Eso te permite usar el try! y ? y tener una solución bastante ergonómica.

¿Es esa la forma más idiomática de hacerlo?

De manera idiomática, diría que una biblioteca tendrá un número pequeño (quizás 1-3) de tipos de error primario que están expuestos. Es probable que estos sean enumeraciones de otros tipos de error. Esto permite a los consumidores de su caja no tratar con una explosión de tipos. Por supuesto, esto depende de su API y de si tiene sentido agrupar algunos errores o no.

Otra cosa a tener en cuenta es que cuando elige incrustar datos en el error, eso puede tener consecuencias de gran alcance. Por ejemplo, la biblioteca estándar no incluye un nombre de archivo en los errores relacionados con el archivo. Si lo hace, agregaría sobrecarga a cada error de archivo. La persona que llama al método generalmente tiene el contexto relevante y puede decidir si ese contexto debe agregarse al error o no.

Recomiendo hacer esto a mano unas cuantas veces para ver cómo todas las piezas van juntas. Una vez que tengas eso, te cansarás de hacerlo manualmente. Luego puede revisar cajas como quick-error , error-chain o failure que proporcionan macros para reducir la placa de la caldera.

Mi biblioteca preferida es de error rápido, así que aquí hay un ejemplo de uso de ese tipo de error original:

#[macro_use] extern crate quick_error; quick_error! { #[derive(Debug)] enum MyError { Gizmo { description("Refrob the Gizmo") } WidgetNotFound(widget_name: String) { description("The widget could not be found") display(r#"The widget "{}" could not be found"#, widget_name) } } } fn foo() -> Result<(), MyError> { Err(MyError::WidgetNotFound("Quux".to_string())) } fn main() { println!("{:?}", foo()); }

Tenga en cuenta que he eliminado el sufijo de Error redundante en cada valor de enumeración. También es común simplemente llamar al Error tipo y permitir que el consumidor prefija el tipo ( mycrate::Error ) o cambiarle el nombre al importar ( use mycrate::Error as FooError ).

1 Antes de la implementación de RFC 2504 , la description era un método requerido.


La caja custom_error permite la definición de tipos de error personalizados con menos repetición de lo que se propuso anteriormente:

custom_error!(MyError Io{source: io::Error} = "input/output error", WidgetNotFoundError{name: String} = "could not find widget ''{name}''", GizmoError = "A gizmo error occurred!" );

Descargo de responsabilidad: Soy el autor de esta caja.