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:

enum Result<T, E> {
    Ok(T),
    Err(E),
}
  • Ok(T): Indica que l'operació ha tingut èxit i conté un valor de tipus T.
  • Err(E): Indica que l'operació ha fallat i conté un valor de tipus E, 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

  1. Funció divide:

    • Accepta dos paràmetres dividend i divisor de tipus f64.
    • Retorna un Result<f64, String>.
    • Si el divisor és zero, retorna un Err amb un missatge d'error.
    • Si no, retorna un Ok amb el resultat de la divisió.
  2. 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.

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

  1. 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.
  2. 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.

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.

© Copyright 2024. Tots els drets reservats