-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from RustLangES/error_handling
Error handling
- Loading branch information
Showing
6 changed files
with
586 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
--- | ||
title: 'Result' | ||
description: 'Result es una enumeración en Rust que se utiliza para representar valores que pueden fallar' | ||
draft: true | ||
data: | ||
type: 'custom' | ||
topicLevel: 'start' | ||
position: | ||
x: 320 | ||
y: 620 | ||
width: 320 | ||
sourcePosition: | ||
error-handling: 'bottom' | ||
externalLinks: | ||
- name: 'Libro Oficial' | ||
english: false | ||
link: 'https://book.rustlang-es.org/ch06-01-defining-an-enum' | ||
- name: 'Comprehensive Rust' | ||
english: false | ||
link: 'https://google.github.io/comprehensive-rust/es/std-types/result.html' | ||
- name: 'Documentacion Oficial' | ||
english: true | ||
link: 'https://doc.rust-lang.org/stable/std/result' | ||
- name: '¿Cómo almacena Rust los enum en memoria?' | ||
english: false | ||
link: 'https://blog.rustlang-es.org/articles/como-almacena-rust-los-enum-en-memoria' | ||
--- | ||
## El Tipo `Result` en Rust: Manejo Seguro de Errores | ||
|
||
Uno de los principios fundamentales de Rust es la seguridad, tanto en la concurrencia como en el manejo de errores. En lugar de depender de excepciones como en otros lenguajes, Rust utiliza el tipo `Result` para manejar errores de forma explícita y segura. Este enfoque reduce la posibilidad de errores inesperados y garantiza que los desarrolladores gestionen los errores correctamente. | ||
|
||
### ¿Qué es un `Result`? | ||
|
||
`Result` es un enum predefinido en Rust que se utiliza para representar el resultado de operaciones que pueden fallar. Su definición es la siguiente: | ||
|
||
```rust | ||
enum Result<T, E> { | ||
Ok(T), | ||
Err(E), | ||
} | ||
``` | ||
|
||
- `Ok(T)`: Indica que la operación fue exitosa y contiene un valor del tipo `T`. | ||
- `Err(E)`: Indica que la operación falló y contiene un valor del tipo `E`, que normalmente describe el error. | ||
|
||
### Funciones Comunes para Trabajar con `Result` | ||
|
||
Rust proporciona múltiples métodos para manipular y controlar el flujo de errores de manera explícita. Algunas de las funciones más comunes son: | ||
|
||
- **is_ok() e is_err():** Estas funciones permiten verificar si un `Result` contiene un valor exitoso o un error. | ||
|
||
```rust | ||
let result: Result<i32, &str> = Ok(10); | ||
assert!(result.is_ok()); | ||
|
||
let error: Result<i32, &str> = Err("Error!"); | ||
assert!(error.is_err()); | ||
``` | ||
|
||
- **unwrap() y expect():** Extraen el valor de un `Result`. Si es un `Ok`, devuelven el valor; si es un `Err`, `unwrap()` causa un pánico. `expect()` es similar, pero permite proporcionar un mensaje de error personalizado. | ||
|
||
```rust | ||
let result: Result<i32, &str> = Ok(5); | ||
let value = result.unwrap(); // Devuelve 5 | ||
|
||
let error: Result<i32, &str> = Err("Error!"); | ||
let value = error.expect("Algo salió mal"); // Causa un pánico con el mensaje proporcionado | ||
``` | ||
|
||
- **map() y map_err():** `map()` permite aplicar una función al valor contenido en `Ok`, mientras que `map_err()` aplica una función al valor contenido en `Err`. | ||
|
||
```rust | ||
let result: Result<i32, &str> = Ok(2); | ||
let doubled = result.map(|x| x * 2); | ||
assert_eq!(doubled, Ok(4)); | ||
|
||
let error: Result<i32, &str> = Err("Error!"); | ||
let new_error = error.map_err(|e| format!("Ocurrió: {}", e)); | ||
assert_eq!(new_error, Err("Ocurrió: Error!".to_string())); | ||
``` | ||
|
||
- **and_then():** Permite encadenar operaciones que también devuelven `Result`, facilitando la propagación de errores. | ||
|
||
```rust | ||
let result: Result<i32, &str> = Ok(2); | ||
let chained_result = result.and_then(|x| Ok(x * 3)); | ||
assert_eq!(chained_result, Ok(6)); | ||
``` | ||
|
||
### Pattern Matching con `Result` | ||
|
||
El pattern matching es una técnica poderosa en Rust que se usa a menudo para manejar `Result`. Con `match`, puedes manejar tanto los casos exitosos como los errores de manera explícita: | ||
|
||
```rust | ||
let result: Result<i32, &str> = Ok(10); | ||
|
||
match result { | ||
Ok(value) => println!("El valor es: {}", value), | ||
Err(error) => println!("Error: {}", error), | ||
} | ||
``` | ||
|
||
### Interactuar con Múltiples `Result` | ||
|
||
Cuando trabajas con múltiples resultados que pueden fallar, puedes combinarlos utilizando combinadores o emplear pattern matching para manejar las diversas posibilidades. Aquí un ejemplo sencillo usando `and_then()` para encadenar operaciones que pueden fallar: | ||
|
||
```rust | ||
let x: Result<i32, &str> = Ok(2); | ||
let y: Result<i32, &str> = Ok(3); | ||
|
||
let result = x.and_then(|x_val| { | ||
y.map(|y_val| x_val + y_val) | ||
}); | ||
|
||
assert_eq!(result, Ok(5)); | ||
``` | ||
|
||
### Funcionamiento en Memoria | ||
|
||
El tipo `Result`, al igual que `Option`, es representado de manera eficiente en memoria. Dado que `Result` es un enum, el compilador ajusta su representación en memoria según el tipo de datos que contiene. Al trabajar con un `Result`, Rust optimiza el almacenamiento para que no haya un sobrecoste significativo en comparación con otras representaciones de errores. | ||
|
||
Cuando se utiliza `Result`, el tamaño en memoria depende tanto del valor contenido en `Ok` como del valor contenido en `Err`. Si bien ambos pueden ser diferentes, el compilador se encarga de ajustar su representación para minimizar el espacio de almacenamiento. | ||
|
||
### Comparación con `Option` | ||
|
||
A diferencia de `Option`, que representa la presencia o ausencia de un valor, `Result` se utiliza principalmente para manejar operaciones que pueden fallar. Aunque ambos son enums, `Result` es más adecuado para representar errores porque incluye el valor `Err` que proporciona información adicional sobre qué salió mal. | ||
|
||
### Ejemplo Completo de Uso de `Result` | ||
|
||
Aquí un ejemplo práctico de cómo podrías utilizar `Result` para manejar una operación de apertura de archivos, que puede fallar si el archivo no existe: | ||
|
||
```rust | ||
use std::fs::File; | ||
use std::io::{self, Read}; | ||
|
||
fn leer_archivo(path: &str) -> Result<String, io::Error> { | ||
let mut archivo = File::open(path)?; | ||
let mut contenido = String::new(); | ||
archivo.read_to_string(&mut contenido)?; | ||
Ok(contenido) | ||
} | ||
|
||
fn main() { | ||
match leer_archivo("archivo.txt") { | ||
Ok(contenido) => println!("Contenido: {}", contenido), | ||
Err(error) => println!("No se pudo leer el archivo: {}", error), | ||
} | ||
} | ||
``` | ||
|
||
### Conclusión | ||
|
||
El tipo `Result` es una herramienta poderosa para el manejo seguro de errores en Rust. Al ser un enum con las variantes `Ok` y `Err`, te obliga a manejar explícitamente los posibles fallos en las operaciones. Gracias a métodos como `map()`, `and_then()` y `unwrap()`, junto con el pattern matching, el manejo de errores en Rust es mucho más robusto y menos propenso a errores que en otros lenguajes. Además, al ser altamente eficiente en memoria, `Result` es una elección óptima para el manejo de errores en aplicaciones de alta performance. |
Oops, something went wrong.