← Rust EspañolChapter 09 of 13

Manejo de Errores

## Objetivos de Aprendizaje - Comprender panic vs Result - Dominar el tipo Option - Usar Result para errores recuperables - Propagar errores con el operador ? - Construir manejo de errores robusto ## Filosofia del Manejo de Errores Rust tiene dos categorias de errores: - **Recuperables**: Usar `Result` - **Irrecuperables**: Usar `panic!` ## Panic ### Cuando Usar Panic - Se violan invariantes (bug en el codigo) - Ejemplo: intentar acceder a un indice fuera de limites ### Usando panic ```rust fn main() { panic!("crash and burn"); } ``` ### Salida de Panic ```text thread 'main' panicked at 'crash and burn', src/main.rs:2:5 note: run with RUST_BACKTRACE=1 for a backtrace. ``` ### Backtrace ```bash RUST_BACKTRACE=1 cargo run ``` ### unwrap y expect ```rust fn main() { // unwrap: devuelve el valor o hace panic let x = Some("value").unwrap(); // expect: devuelve el valor o hace panic con mensaje let x = Some("value").expect("Expected a value"); // En None/Err let x: Option<&str> = None; x.unwrap(); // Panic } ``` ### unwrap en Result ```rust fn main() { // unwrap en Ok let x: Result = Ok(42); println!("{}", x.unwrap()); // 42 // unwrap en Err - panic let x: Result = Err("error"); x.unwrap(); // Panic con "error" // expect con mensaje let x: Result = Err("error"); x.expect("Should be Ok"); // Panic con "Should be Ok" } ``` ## Manejo de Option ### unwrap_or ```rust fn main() { let x = Some("value"); assert_eq!(x.unwrap_or("default"), "value"); let x: Option<&str> = None; assert_eq!(x.unwrap_or("default"), "default"); } ``` ### unwrap_or_else ```rust fn main() { let x: Option = None; // Evaluacion perezosa let result = x.unwrap_or_else(|| { println!("Computing default..."); 42 }); } ``` ### map en Option ```rust fn main() { let x = Some(5); let doubled = x.map(|n| n * 2); // Some(10) let squared = x.map(|n| n * n); // Some(25) let x: Option = None; let doubled = x.map(|n| n * 2); // None } ``` ### and_then (flatmap) ```rust fn main() { let x = Some(5); let result = x.and_then(|n| Some(n * 2)); // Some(10) let x: Option = None; let result = x.and_then(|n| Some(n * 2)); // None } ``` ### or y or_else ```rust fn main() { let x = Some(1); let y = Some(2); assert_eq!(x.or(y), Some(1)); // x es Some, mantenerlo let x: Option = None; assert_eq!(x.or(y), Some(2)); // x es None, usar y let x = None; let default = x.or_else(|| Some(42)); // valor por defecto perezoso } ``` ### filter ```rust fn main() { let x = Some(10); let result = x.filter(|n| n > 5); // Some(10) let result = x.filter(|n| n > 15); // None } ``` ## Tipo Result ### Uso Basico ```rust use std::fs::File; fn main() { let file = File::open("hello.txt"); match file { Ok(_) => println!("File opened successfully"), Err(e) => println!("Error opening file: {:?}", e), } } ``` ### Metodos de Result ```rust fn main() { let x: Result = Ok(5); x.is_ok(); // true x.is_err(); // false x.ok(); // Some(5) x.err(); // None x.unwrap_or(0); // 5 x.unwrap_or_else(|_| 0); // 5 x.map(|n| n * 2); // Ok(10) x.map_err(|e| format!("Error: {}", e)); } ``` ### Recolectando Results ```rust fn main() { let results: Vec> = vec![Ok(1), Ok(2), Err("error")]; // Recolectar como Vec de valores (falla si hay algun Err) // let values: Result, &str> = results.into_iter().collect(); // Particionar en Ok y Err let (oks, errs): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok); let values: Vec<_> = oks.into_iter().map(Result::unwrap).collect(); println!("{:?} {:?}", values, errs); // [1, 2] [Err("error")] } ``` ## El Operador ? ### Fundamentos del Operador ? ```rust use std::fs::File; use std::io; fn read_file() -> Result { let mut file = File::open("hello.txt")?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } ``` ### ? con Option ```rust fn first_word(s: &str) -> Option<&str> { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return Some(&s[0..i]); } } None } fn main() { let text = "hello world"; let first = first_word(text).ok_or("No first word")?; println!("{}", first); } ``` ### Encadenando ? ```rust use std::fs::File; use std::io; use std::io::Read; fn read_file_contents(path: &str) -> Result { let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } fn main() { match read_file_contents("hello.txt") { Ok(contents) => println!("{}", contents), Err(e) => eprintln!("Error: {:?}", e), } } ``` ### Trait From para Conversion ```rust use std::fs::File; use std::io; use std::num::ParseIntError; fn read_number() -> Result { let s = "42"; let n: i32 = s.parse()?; // ParseIntError Ok(n) } ``` ## Tipos de Error Personalizados ### Definir Enum de Error ```rust use std::fmt; enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError), } impl fmt::Display for MyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MyError::Io(e) => write!(f, "IO error: {}", e), MyError::Parse(e) => write!(f, "Parse error: {}", e), } } } impl From for MyError { fn from(err: std::io::Error) -> Self { MyError::Io(err) } } impl From for MyError { fn from(err: std::num::ParseIntError) -> Self { MyError::Parse(err) } } ``` ### Usando Errores Personalizados ```rust fn read_and_parse(path: &str) -> Result { let contents = std::fs::read_to_string(path)?; let n: i32 = contents.trim().parse()?; Ok(n) } ``` ## Mejores Practicas ### No Usar unwrap en Codigo de Libreria ```rust // Mal: codigo de libreria que hace panic pub fn get(&self, key: &str) -> &str { self.map.get(key).unwrap() // Panic si falta } // Bien: devolver Result pub fn get(&self, key: &str) -> Option<&str> { self.map.get(key) } ``` ### Usar expect para Valores Conocidos ```rust fn main() { // Cuando estas seguro de que el valor existe let x = [1, 2, 3]; let first = x.first().expect("Array should not be empty"); } ``` ### Propagar Errores ```rust use std::io; fn read_file(path: &str) -> io::Result { let mut file = io::File::open(path)?; // Propagar error let mut contents = String::new(); file.read_to_string(&mut contents)?; // Propagar error Ok(contents) } ``` ## Resumen - `panic!` para errores irrecuperables - `unwrap()` devuelve el valor o hace panic - `expect()` devuelve el valor o hace panic con mensaje - `Option` para valores que pueden no existir (Some/None) - `Result` para errores recuperables (Ok/Err) - El operador `?` propaga errores - `unwrap_or()` y `unwrap_or_else()` proporcionan valores por defecto - `map()` transforma valores Option/Result - Crear tipos de error personalizados con trait From para conversion

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →