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
dividend
idivisor
de tipusf64
. - Retorna un
Result<f64, String>
. - Si el
divisor
és zero, retorna unErr
amb un missatge d'error. - Si no, retorna un
Ok
amb el resultat de la divisió.
- Accepta dos paràmetres
-
Funció
main
:- Utilitza un
match
per 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_path
de 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
match
per 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
.