IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ sur la programmation en langage RustConsultez toutes les FAQ

Nombre d'auteurs : 1, nombre de questions : 95, dernière mise à jour : 21 juillet 2018  Ajouter une question

 

Cette FAQ a été réalisée pour répondre aux questions les plus fréquemment posées sur la programmation en langage Rust. Nous vous recommandons de la consulter avant de poser vos questions sur le forum Rust.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle contient sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci.

Toute nouvelle question/réponse est la bienvenue, vous pouvez proposer vos questions réponses par e-mail (voir le lien en bas de page) au(x) responsable(s) de la rubrique Rust ou mieux en postant votre proposition à la publication.
Vous pouvez participer à l'amélioration des questions réponses en postant directement dans cette FAQ. Une validation par le(s) responsable(s) de la rubrique Rust sera requise avant que vos contributions ne soient visibles.

Sur ce, nous vous souhaitons une bonne lecture.

SommaireLangageGestion des erreurs (17)
précédent sommaire suivant
 

Tout comme les langages impératifs classiques (e.g. C), Rust ne gère pas les erreurs grâce à un système « d'exceptions » comme nous pourrions le retrouver dans des langages plus orientés objet, mais grâce au contenu renvoyé en sortie de fonction.
Plusieurs fonctions (et macros) sont d'ailleurs dédiées à cette gestion (e.g. panic!, unwrap (et ses dérivés), and_then) permettant ainsi de rattraper (d'une manière plus ou moins fine) la situation lorsque les conditions imposées par vos soins ne sont pas respectées.

Cette section regroupe donc un certain nombre de Q/R qui pourraient vous aider à mieux cerner ce système de gestion :

Information
Toutes les Q/R taguées avec l'icône sont considérées comme « en cours de rédaction ». Si vous rencontrez un problème de lecture avec ces Q/R inachevées, ne remontez pas le problème tant qu'elles disposent de ce tag. Merci.

Mis à jour le 25 octobre 2016 Songbird

Oui, bien entendu.

Il existe trois assertions différentes en Rust (toutes encapsulées par une macro) :

1. assert!;
2. assert_eq!;
3. debug_assert!.

Mis à jour le 2 février 2017 Songbird

Il n'est pas possible de créer une structure censée représenter un type d'erreur, comme nous pourrions le faire en Java; Rust ne gère pas les potentielles erreurs de cette manière.

Mis à jour le 2 février 2017 Songbird

La macro panic! pourrait être comparée aux exceptions RuntimeException en Java qui sont, à coup sûr, des erreurs bloquantes.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
public class MyClass  
{ 
	    public static void main(String[] args)  
	    { 
	        throw new RuntimeException("Error !"); 
	        System.out.println("Dead code."); 
	    } 
}

Elle est donc la macro ayant le plus bas niveau parmi les macros et/ou fonctions proposées par la bibliothèque standard ; elle ne prend rien en compte mis à part l'arrêt du programme et l'affichage de la trace de la pile.

Code Rust : Sélectionner tout
1
2
3
4
5
fn main() 
{ 
    panic!("Error !"); 
    println!("Dead code"); 
}

Mis à jour le 25 octobre 2016 Songbird

La méthode unwrap() permet de récupérer la donnée contenue par son wrapper et de faire abstraction des « cas d'analyse » avant de la délivrer.
Autrement dit, la méthode unwrap() délivre la donnée enveloppée si l'instance vaut Some() ou Ok(), sinon plante le programme si elle vaut None ou Err().

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
fn main() 
{ 
    let foo : Option<String> = Some("ça passe!".to_string()); 
    let bar : Option<String> = None; 
    let baz : Result<String, String> = Ok("ça passe!".to_string()); 
    let bing : Result<String, String> = Err("ça casse!".to_string()); 
  
    println!("{} {} {} {}", foo.unwrap(), bar.unwrap(), baz.unwrap(), bing.unwrap()); 
}

Mis à jour le 25 octobre 2016 Songbird

Voir aussi :
Tester l'exemple (pensez à isoler les appels de la méthode si vous ne souhaitez pas faire planter votre programme.)
Qu'est-ce que la structure Option<T> ?
Qu'est-ce que la structure Result<T, E> ?

La méthode unwrap_or() fonctionne exactement comme la méthode originelle, mais elle permet d'éviter de faire « paniquer » le programme, et donc l'arrêt de l'exécution, en nous permettant de passer une valeur par défaut à renvoyer si le wrapper visé ne contient rien initialement.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
fn main() 
{ 
    let foo : Option<String> = Some("ça passe!".to_string()); 
    let bar : Option<String> = None; 
    let baz : Result<String, String> = Ok("ça passe!".to_string()); 
    let bing : Result<String, String> = Err("ça casse!".to_string()); 
  
    println!("{} {} {} {}", foo.unwrap(), bar.unwrap_or(String::from("ça passe, mais de justesse !")), baz.unwrap(), bing.unwrap_or(String::from("On évite de faire planter le programme."))); 
    /*  
        Pensez à isoler les appels de la méthode si vous ne souhaitez pas faire planter votre programme. 
    */ 
}

Mis à jour le 25 octobre 2016 Songbird

Voir aussi:
Tester l'exemple

La méthode unwrap_or_else fonctionne exactement comme unwrap_or, mais proposera de passer en paramètre une fonction à la place d'une simple donnée.

Attention, Option<T> et Result<T, E> l'implémentent toutes les deux, mais pas de la même manière.
L'une l'implémente de manière à passer en paramètre une closure, l'autre à passer une fonction déclarée et identifiée dans un premier temps.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn bang(arg: String) -> String 
{ 
    return "Chef, on a eu une erreur: ".to_string() + arg.as_str(); 
} 
fn main() 
{ 
    let foo : Option<String> = Some("ça passe!".to_string()); 
    let bar : Option<String> = None; 
    let baz : Result<String, String> = Ok("ça passe!".to_string()); 
    let bing : Result<String, String> = Err("ça casse!".to_string()); 
  
    bar.unwrap_or_else(|| { return "On évite la casse !".to_string(); }); 
    println!("{}", bing.unwrap_or_else(bang)); 
}

Note : le paramètre que reçoit la fonction bang n'est ni plus ni moins ce que vous avez renseigné dans le constructeur de l'instance Err() bing. Gardez cela en tête lorsque vous souhaiterez effectuer des opérations sur ce paramètre dans le corps de votre fonction.

Mis à jour le 25 octobre 2016 Songbird

Elle permet de modifier la donnée contenue. Exemple :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
fn main() { 
    let foo = vec![1, 2, 3]; 
    let foo2: Vec<_> = foo.iter().map(|entry| format!("> {}", entry)).collect(); 
  
    for entry in foo2 { 
        println!("-> \"{}\"", entry); 
    } 
}


Ce qui affichera :

Code : Sélectionner tout
1
2
3
-> "> 1" 
-> "> 2" 
-> "> 3"

Mis à jour le 3 juillet 2018 Songbird

La méthode and_then() permet d'effectuer des opérations sur la structure qui l'implémente, puis renvoie une nouvelle instance de cette dernière.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
fn concat(arg: &str) -> Option<String> 
{ 
    Some(arg.to_string() + "world!") 
} 
fn main() 
{ 
    let foo = Some("Hello "); 
    println!("{}", foo.and_then(concat).unwrap()); 
}

Actuellement, les structures qui implémentent la méthode and_then() sont :
  1. Option<T>;
  2. Result<T, E>;

Mis à jour le 25 octobre 2016 Songbird

Voir aussi :
À quoi sert la méthode unwrap() ?
Qu'est-ce que la structure Result<T, E> ?
Qu'est-ce que la structure Option<T> ?

La macro try! permet de s'assurer de l'intégrité de la ressource.
Si la ressource enveloppée par la macro try! est intègre, elle sera bindée à l'identificateur qui lui est assigné.
Sinon, try! effectue un retour, renvoi prématuré.

Note

Attention toutefois à ne pas oublier qu'une fonction usant de cette macro doit forcément renvoyer une instance de Result<(), io::Error> (le type de la valeur renvoyée en cas de succès est arbitaire).

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
fn foo(string: &String) -> Result<(), std::io::Error>  
{ 
    try!(std::fs::File::create("my_file.txt")); 
    println!("Une chance sur deux pour que je sois du code mort !"); 
    Ok(()) 
} 
  
fn bar(string: &String) -> std::io::Result<()>  
{ // fonctionne également avec l'alias de Result<T, E> 
    try!(std::fs::File::create("my_file.txt")); 
    println!("Une chance sur deux pour que je sois du code mort !"); 
    Ok(()) 
}

Note(bis)

Depuis la version 1.13, la macro try! a été plus ou moins remplacée par l'opérateur ?.
Elle peut toujours être utilisée, toutefois, privilégiez cet opérateur autant que possible.

L'exemple ci-dessus peut donc être transposé de cette manière:

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
use std::io::Error; 
fn foo(string: &String) -> Result<(), Error>  
{ 
    std::fs::File::create("my_file.txt")?; 
    println!("Une chance sur deux pour que je sois du code mort !"); 
    Ok(()) 
} 
  
fn bar(string: &String) -> std::io::Result<()>  
{ // fonctionne également avec l'alias de Result<T, E> 
    std::fs::File::create("my_file.txt")?; 
    println!("Une chance sur deux pour que je sois du code mort !"); 
    Ok(()) 
}

Mis à jour le 3 juillet 2018 Songbird

Voir aussi:

Le document abordant la gestion d'erreur avec les nouvelles fonctionnalités du langage.

La macro assert! capture deux types « d'expressions » différents :
Les expressions à proprement parler, qui pourraient être illustrées par les exemples suivants :

Code Rust : Sélectionner tout
2 * 2, ifelse …, foo() ;


Les « tokens tree » qui pourraient être illustrés par n'importe quoi d'autres figurant dans la syntaxe du langage. (puisque, dans l'absolu, le compilateur représente tout ce qui est rédigé dans les fichiers sources grâce à une nomenclature bien à lui)

Donc si nous récupérons le code source raccourci de la documentation, cela donne ceci :

Code Rust : Sélectionner tout
1
2
3
4
5
macro_rules! assert { 
    ( $ cond : expr ) => { ... }; 
    ( 
$ cond : expr , $ ( $ arg : tt ) + ) => { ... }; 
}

Si certaines choses vous échappent, n'hésitez pas à vous rendre sur les liens proposés en bas de cette Q/R.

À quoi sert le second paramètre ?

Le second peut, par exemple, accueillir un message personnalisé pour la macro panic! facilitant ainsi le débogage.

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
fn foo(arg: Option<String>) -> () 
{ 
    let bar : String = String::from("Hello world!"); 
    let mut some : Option<String> = None; 
    assert!(!arg.is_none(), "Arg is None"); 
    assert!(arg.unwrap().eq(&bar), "arg n'est pas égal à bar"); 
} 
  
fn main() -> () 
{ 
    foo(Some("Ok".to_string())); 
    foo(None); 
}

Mis à jour le 25 octobre 2016 Songbird

Voir aussi :
Visionner le résultat de l'exemple (requiert une connexion internet) ;
Comment utiliser une macro ?

« assert_eq! » est un dérivé de la macro « assert! » et permet de tester directement l'égalité de deux objets1.
Bien entendu, elle hérite également du message personnalisé pour la macro « panic! ».

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
fn foo(arg: Option<String>) -> () 
{ 
    let bar : String = String::from("Hello world!"); 
    let mut some : Option<String> = None; 
    assert!(!arg.is_none(), "Arg is None"); 
    assert_eq!(arg.unwrap(), bar, "arg n'est pas égal à bar"); 
} 
  
fn main() -> () 
{ 
    foo(Some("Ok".to_string())); 
    foo(None); 
}

1. Le terme « objet » est ici utilisé pour désigner toutes les entités pouvant être comparées à d'autres (cela ne concerne donc pas que les instances des structures).

Mis à jour le 2 février 2017 Songbird

Voir aussi :
Visionner le résultat de l'exemple (requiert une connexion internet) ;
Comment utiliser une macro ?

Où puis-je l'utiliser ?
« debug_assert! » ainsi que ses dérivées (« debug_assert_eq! ») ne sont compilées que lorsque le code source est compilé en mode débogage (mode par défaut de rustc).
Vous ne devez pas compter sur ces assertions pour contrôler le flux de votre programme en production, assurez-vous toujours d'avoir une assertion compilée en mode release.

Information
Si vous souhaitez toutefois les utiliser dans un binaire optimisé, vous devez passer l'argument -C debug-assertions au compilateur.

Comment l'utiliser ?
En dehors du contexte dans lequel ces assertions doivent être déclarées, la manière dont elles sont utilisées ne change pas.

Mis à jour le 2 février 2017 Songbird

Option est une énumération contenant deux constructeurs différents : Some(T) et None.
Option est en quelque sorte un wrapper, conteneur permettant de vérifier l'intégrité des données contenues.

Mis à jour le 30 octobre 2016 Songbird

Pour utiliser les variantes de l'énumération, il faut savoir à quoi elles correspondent.

  • Some(T) représente un binding valide.
  • None représente un binding invalide.


Code Rust : Sélectionner tout
1
2
3
4
5
fn main() 
{ 
    let foo : Option<String> = Some(String::from("Binding valide")); 
    let bar : Option<String> = None; //binding invalide, ne contient rien 
}

Mis à jour le 30 octobre 2016 Songbird

Result<T, E> est une énumération contenant deux variantes :

1. Ok(T),
2. Err(E).

Elle permet de gérer convenablement les cas où l'entrée T ne correspond pas à nos attentes et ainsi le communiquer au reste du programme pour que l'incident soit rattrapé plus loin si besoin.

Mis à jour le 2 février 2017 Songbird

L'utilisation de cette énumération requiert quelques notions quant à la gestion des erreurs avec Rust; Ce dernier ne permettant pas l'utilisation des exceptions, cette structure vous permettra de conserver l'entrée si elle correspond à vos attentes, ou le message d'erreur si quelque chose ne s'est pas passé correctement.

Voici un exemple simple de gestion d'erreur :

Code Rust : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn foo<'a, 'b>(arg: Option<&'a str>) -> Result<String, &'b str> { 
    if let Some(content) = arg { 
        let unwrapping = arg.unwrap(); 
        Ok(unwrapping.to_string()) 
    } else { 
        Err("L'argument ne contient rien.") 
    } 
} 
  
fn main() { 
    match foo(None) { 
        Ok(content) => println!("Ok: {}", content), 
        Err(err) => println!("Error: {}", err.to_string()), 
    } 
}

Mis à jour le 2 février 2017 Songbird

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.