En Rust, la gestió d'errors és una part fonamental del llenguatge, i es fa principalment mitjançant el tipus Result. Aquest tipus permet als programes manejar errors de manera explícita i segura. En aquesta secció, aprendrem com utilitzar Result per gestionar errors de manera efectiva.
Què és Result?
El tipus Result és una enumeració que es defineix de la següent manera:
Ok(T): Indica que l'operació ha tingut èxit i conté un valor de tipusT.Err(E): Indica que l'operació ha fallat i conté un valor de tipusE, que normalment és una descripció de l'error.
Exemple Bàsic
Vegem un exemple bàsic d'ús de Result:
fn divide(dividend: f64, divisor: f64) -> Result<f64, String> {
if divisor == 0.0 {
Err(String::from("No es pot dividir per zero"))
} else {
Ok(dividend / divisor)
}
}
fn main() {
match divide(4.0, 2.0) {
Ok(result) => println!("El resultat és: {}", result),
Err(e) => println!("Error: {}", e),
}
match divide(4.0, 0.0) {
Ok(result) => println!("El resultat és: {}", result),
Err(e) => println!("Error: {}", e),
}
}Explicació del Codi
-
Funció
divide:- Accepta dos paràmetres
dividendidivisorde tipusf64. - Retorna un
Result<f64, String>. - Si el
divisorés zero, retorna unErramb un missatge d'error. - Si no, retorna un
Okamb el resultat de la divisió.
- Accepta dos paràmetres
-
Funció
main:- Utilitza un
matchper gestionar el resultat de la funciódivide. - Si el resultat és
Ok, imprimeix el resultat. - Si el resultat és
Err, imprimeix el missatge d'error.
- Utilitza un
Propagació d'Errors
Rust proporciona una manera còmoda de propagar errors utilitzant l'operador ?. Aquest operador es pot utilitzar per simplificar el codi que gestiona errors.
Exemple amb l'Operador ?
fn read_file_content(file_path: &str) -> Result<String, std::io::Error> {
let mut file = std::fs::File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
fn main() {
match read_file_content("example.txt") {
Ok(content) => println!("Contingut del fitxer: {}", content),
Err(e) => println!("Error llegint el fitxer: {}", e),
}
}Explicació del Codi
-
Funció
read_file_content:- Accepta un
file_pathde tipus&str. - Retorna un
Result<String, std::io::Error>. - Utilitza l'operador
?per propagar errors de les operacions de fitxer. - Si totes les operacions tenen èxit, retorna el contingut del fitxer dins d'un
Ok.
- Accepta un
-
Funció
main:- Utilitza un
matchper gestionar el resultat de la funcióread_file_content. - Si el resultat és
Ok, imprimeix el contingut del fitxer. - Si el resultat és
Err, imprimeix el missatge d'error.
- Utilitza un
Exercicis Pràctics
Exercici 1: Funció de Divisió
Escriu una funció safe_divide que accepti dos enters i retorni un Result<i32, String>. La funció ha de retornar un error si el divisor és zero.
fn safe_divide(a: i32, b: i32) -> Result<i32, String> {
// Implementa la funció aquí
}
fn main() {
// Prova la funció amb diferents valors
}Solució
fn safe_divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("No es pot dividir per zero"))
} else {
Ok(a / b)
}
}
fn main() {
match safe_divide(10, 2) {
Ok(result) => println!("El resultat és: {}", result),
Err(e) => println!("Error: {}", e),
}
match safe_divide(10, 0) {
Ok(result) => println!("El resultat és: {}", result),
Err(e) => println!("Error: {}", e),
}
}Exercici 2: Lectura de Fitxer
Escriu una funció read_first_line que accepti un camí de fitxer i retorni la primera línia del fitxer com un Result<String, std::io::Error>.
fn read_first_line(file_path: &str) -> Result<String, std::io::Error> {
// Implementa la funció aquí
}
fn main() {
// Prova la funció amb diferents fitxers
}Solució
use std::fs::File;
use std::io::{self, BufRead, BufReader};
fn read_first_line(file_path: &str) -> Result<String, std::io::Error> {
let file = File::open(file_path)?;
let mut reader = BufReader::new(file);
let mut first_line = String::new();
reader.read_line(&mut first_line)?;
Ok(first_line)
}
fn main() {
match read_first_line("example.txt") {
Ok(line) => println!("Primera línia: {}", line),
Err(e) => println!("Error llegint el fitxer: {}", e),
}
}Resum
En aquesta secció, hem après com utilitzar el tipus Result per gestionar errors en Rust. Hem vist com utilitzar match per gestionar resultats i com l'operador ? pot simplificar la propagació d'errors. També hem practicat amb exercicis per reforçar aquests conceptes. En la següent secció, explorarem la gestió d'errors amb el tipus Option.
