Retour de String en Rust

Alors voila, je veux écrire une fonction qui appelle une commande shell et retourne la chaîne de caractères.

Avec la cagette standard std::process::Command c’est plutôt simple il suffit de faire ça :

use std::process::Command;
//..
    let _cmdret = Command::new("cd-discid")
                            .output()
                            .expect("La commande cd-discid a échouée");
  
//..

L’affichage de _cmdret avec un println! qui va bien me donne la forme de la structure retournée :

println!("{:?}", &_cmdret);
//:Sortie ->
Output { status: ExitStatus(unix_wait_status(0)), stdout: "30027f05 5 150 2422 15072 29219 44022 641\n", stderr: "" }

Pour le moment c’est assez simple, si je veux récupérer la chaîne de caractères, il me suffit de prendre le champs stdout :

println!("{:?}", &_cmdret.stdout);
//...
[51, 48, 48, 50, 55, 102, 48, 53, 32, 53, 32, 49, 53, 48, 32, 50, 52, 50, 50, 32, 49, 53, 48, 55, 50, 32, 50, 57, 50, 49, 57, 32, 52, 52, 48, 50, 50, 32, 54, 52, 49, 10]

Rhaa, mais pourquoi ça s’est transformé en vecteur de u8 ?!

Allons bon, convertissons avec std::str :

use std::str
///
    println!("{:?}", str::from_utf8(&_cmdret.stdout));
///sortie ->
Ok("30027f05 5 150 2422 15072 29219 44022 641\n")

On obtient donc une sortie de type Result non ? Notre fonction doit pouvoir s’écrire comme ça alors :

/// Lit le numéro unique du CD se trouvant dans le lecteur
pub fn get_discid() -> Result<String, Box<dyn Error>> {
    let _cmdret = Command::new("cd-discid")
                            .output()
                            .expect("La commande cd-discid a échouée");

    str::from_utf8(&_cmdret.stdout)
}

Sauf que non, ce que je croyais être un enum «Result» c’est transformé en une chaîne de caractères &str :

22 |     str::from_utf8(&_cmdret.stdout)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `&str`

Rajoutons un Ok() pour lui faire plaisir alors :

22 |     Ok(str::from_utf8(&_cmdret.stdout))
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found enum `Result`

Et c’est là que je commence à perdre pied, bin oui t’as trouvé un enum Result, puisque c’est ça que j’attends en retour patate !

En browsant désespérément le web j’ai cru trouver qu’il fallait faire un match sur l’enum pour retourner un nouvel enum (mais j’ai pas compris pourquoi le premier ne convenait pas):

/// Lit le numéro unique du CD se trouvant dans le lecteur
pub fn get_discid() -> Result<String, Box<dyn Error>> {
    let _cmdret = Command::new("cd-discid")
                            .output()
                            .expect("La commande cd-discid a échouée");

    match str::from_utf8(&_cmdret.stdout) {
        Ok(v) => Ok(v.to_string()),
        Err(e) => Err(e.into())
    }
}

À noter qu’il est possible de remplacer le to_string() en into() dans le Ok() mais pas pour le Err().

Bon maintenant ça marche. Mais il me reste un goût amer de celui qui n’a pas compris ce qu’il a écrit. Et j’ai la désagréable impression d’avoir tartiné du code pour pas grand chose !

On doit pouvoir faire plus simple non ?

Bref, la route est encore longue, et c’est pas ce soir que je verrais mes recettes d’histoires terminées 😉

Ce contenu a été publié dans Non classé, avec comme mot(s)-clé(s) , , , . Vous pouvez le mettre en favoris avec ce permalien.

2 réponses à Retour de String en Rust

  1. ~ryder dit :

    On peut faire Ok(std::str::from_utf8(&cmdret.stdout)?.to_string()).
    De mémoire le ? va automatiquement chercher à convertir l’erreur dans le type attendu en retour, ce qui évite un into() explicite.
    Autre avantage, si jamais on veut faire un traitement derrière sur la chaîne retournée, c’est plus facile. Par exemple :

    let s = std::str::from_utf8(&cmdret.stdout)?.to_string();
    Ok(do_stuff(s))

    Quand tu dis “bin oui t’as trouvé un enum Result, puisque c’est ça que j’attends”, tu ne fais pas attention à la partie “soulignée” de l’erreur, qui n’inclue pas le Ok.

    • admin dit :

      Merci ~ryder 🙂

      Le ? simplifie en effet le code et fonctionne bien.

      Quand tu dis “bin oui t’as trouvé un enum Result, puisque c’est ça que j’attends”, tu ne fais pas attention à la partie “soulignée” de l’erreur, qui n’inclue pas le Ok.

      J’avoue avoir fait un raccourci foireux. Mon problème est que si je supprime le Ok(), en toute logique, je suis sensé me retrouver avec un enum de type Result non ?

      Or ça n’est pas le cas, si je fait ça le compilateur voit un &str ! Il faudrait savoir.


      22 | str::from_utf8(&_cmdret.stdout)
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `&str`

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.