io::Error în Rust

Intrare și ieșire: std::io Rust 1.0 (Error::other: 1.74)

Eroarea operațiilor de intrare/ieșire; kind() dă categoria (NotFound, PermissionDenied...), iar new() creează una proprie.

Sintaxă
use std::io::{Error, ErrorKind};

fn new<E>(kind: ErrorKind, error: E) -> Error   // E: Into<Box<dyn Error + Send + Sync>>
fn other<E>(error: E) -> Error
fn kind(&self) -> ErrorKind

Ce face io::Error

Toate funcțiile din std::fs și std::io returnează io::Error la eșec. Mesajul (prin Display) vine de obicei de la sistemul de operare, de exemplu No such file or directory (os error 2). Metoda kind() returnează un ErrorKind, o categorie independentă de sistem, pe care poți face match.

Categorii frecvente: NotFound, PermissionDenied, AlreadyExists, InvalidInput, InvalidData, UnexpectedEof, Interrupted, Other. Lista este marcată #[non_exhaustive], deci un match pe ea trebuie să aibă și ramura _.

io::Error::new(ErrorKind::InvalidData, "mesaj") creează o eroare proprie, utilă când funcția ta returnează io::Result. io::Error::other("mesaj") este forma scurtă pentru ErrorKind::Other.

Parametri

Parametru Descriere
kind Categoria erorii (la new).
error Mesajul (un text) sau altă eroare care este împachetată.

Ce returnează

new/other: un io::Error. kind: ErrorKind.

Exemple

Exemplul 1: Reacție diferită după tipul erorii

use std::fs::{self, File};
use std::io::ErrorKind;

fn main() {
    fs::write("exista.txt", "x").unwrap();
    for (cale, nou) in [("lipsa.txt", false), ("exista.txt", true)] {
        let r = if nou { File::create_new(cale) } else { File::open(cale) };
        match r {
            Ok(_) => println!("{cale}: OK"),
            Err(e) => match e.kind() {
                ErrorKind::NotFound => println!("{cale}: nu există ({e})"),
                ErrorKind::AlreadyExists => println!("{cale}: există deja ({e})"),
                ErrorKind::PermissionDenied => println!("{cale}: fără permisiune"),
                _ => println!("{cale}: altă eroare: {e}"),
            },
        }
    }
}

Rezultat

lipsa.txt: nu există (No such file or directory (os error 2))
exista.txt: există deja (File exists (os error 17))

Exemplul 2: O eroare proprie într-o funcție cu io::Result

Fișierul există, dar conținutul nu este valid; returnăm InvalidData cu un mesaj clar.

use std::fs;
use std::io::{self, ErrorKind};

fn citeste_port(cale: &str) -> io::Result<u16> {
    let text = fs::read_to_string(cale)?;
    text.trim()
        .parse()
        .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("port invalid „{}”: {e}", text.trim())))
}

fn main() {
    fs::write("port_bun.txt", "8080\n").unwrap();
    fs::write("port_rau.txt", "optzeci\n").unwrap();
    for cale in ["port_bun.txt", "port_rau.txt", "port_lipsa.txt"] {
        match citeste_port(cale) {
            Ok(p) => println!("{cale}: portul {p}"),
            Err(e) => println!("{cale}: {:?}: {e}", e.kind()),
        }
    }
    println!("{}", io::Error::other("serviciul nu răspunde"));
}

Rezultat

port_bun.txt: portul 8080
port_rau.txt: InvalidData: port invalid „optzeci”: invalid digit found in string
port_lipsa.txt: NotFound: No such file or directory (os error 2)
serviciul nu răspunde

Greșeli frecvente

  • Compari mesajul erorii ca text (e.to_string() == "..."): mesajele diferă între sisteme și limbi. Compară e.kind().
  • Scrii un match pe ErrorKind fără ramura _: nu compilează, pentru că enum-ul poate primi variante noi.

Comenzi înrudite

  • io::Result: Prescurtare pentru Result<T, io::Error>, tipul returnat de toate operațiile de intrare/ieșire.
  • Error: Trait-ul comun al tuturor tipurilor de eroare: o eroare se poate afișa (Display, Debug) și poate avea o cauză.
  • Error::source: Returnează eroarea care a cauzat eroarea curentă, dacă există, ca să poți afișa tot lanțul de cauze.
  • Result::is_ok_and: Răspunde cu true dacă rezultatul este Ok și valoarea respectă condiția dată.