web-dev-qa-db-fra.com

Qu'est-ce que le déballage dans Rust et à quoi sert-il?

J'ai ce code qui utilise .unwrap():

fn main() {
    let paths = std::fs::read_dir("/home/user").unwrap();

    for path in paths {
        println!("Name: {}", path.unwrap().path().display());

    }
}

Après avoir regardé la définition de unwrap ,

pub fn unwrap(self) -> T {
  match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
    }
}

Et le signature de read_dir

pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>

Ai-je raison de comprendre que unwrap renvoie le type T qui est passé dans Result?

41
Angel Angel

Dans Rust, lorsque vous avez une opération qui peut retourner un T ou échouer, vous aurez une valeur de type Result<T,E> Ou Option<T> (E sera être la condition d'erreur en cas d'erreur intéressante).

La fonction unwrap(self) -> T vous donnera le T intégré s'il y en a un. Si à la place il n'y a pas un T mais un E ou None alors il paniquera.

Il est préférable de l'utiliser lorsque vous êtes certain de ne pas avoir d'erreur. Si ce n'est pas le cas, il vaut mieux soit faire correspondre le motif à l'erreur, soit utiliser Macro try! Opérateur ? Pour transmettre l'erreur.

Dans votre exemple, l'appel à read_dir() renvoie un io::Result<ReadDir> Car l'ouverture du répertoire peut échouer. Et l'itération du répertoire ouvert renvoie plusieurs valeurs de type io::Result<DirEntry> Car la lecture du répertoire peut également échouer.

Avec try!? Ce serait quelque chose comme ceci:

fn main2() -> std::io::Result<()> {
    let entries = std::fs::read_dir("/home/user")?;

    for entry in entries {
        println!("Name: {}", entry?.path().display());

    }
    Ok(())
}

fn main() {
    let res = main2();

    if let Err(e) = res {
        println!("Error: {}", e);
    }
}

Regardez comment chaque cas d'erreur est vérifié.

(Mis à jour pour utiliser ? Au lieu de try!(). La macro fonctionne toujours, mais ? Est préférable pour le nouveau code).

50
rodrigo