Menu
Coddy logo textTech

La clause where

Fait partie de la section Programmation Orientée Objet du Journey Rust de Coddy. Leçon 42 sur 61.

À mesure que vous ajoutez davantage de contraintes de traits, les signatures de fonctions peuvent devenir difficiles à lire. Considérez une fonction comportant plusieurs paramètres génériques, chacun nécessitant plusieurs traits :

fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
    // ...
}

Cela fonctionne, mais la signature devient chargée. La clause where offre une alternative plus claire en plaçant les contraintes de trait après la liste des paramètres :

fn complex_operation<T, U>(first: T, second: U)
where
    T: Display + Clone,
    U: Debug + Summary,
{
    // ...
}

Les deux versions sont fonctionnellement identiques : la clause where concerne uniquement la lisibilité. Les exigences de chaque type apparaissent sur leur propre ligne, ce qui permet de parcourir facilement les besoins de chaque paramètre générique.

La clause where devient particulièrement utile lorsque les contraintes sont complexes ou lorsque vous avez de nombreux paramètres génériques. Elle permet de garder le nom et les paramètres de la fonction visibles en un coup d’œil, les contraintes étant répertoriées séparément ci-dessous. C’est le style privilégié dans la plupart des bases de code Rust lorsque les contraintes dépassent un simple T: Trait.

challenge icon

Défi

Facile

Construisons un système de traitement des données qui utilise la clause where afin de garder lisibles les contraintes de traits complexes ! Vous allez créer une fonction générique avec plusieurs paramètres de type, chacun nécessitant des traits différents, et organiser proprement les contraintes à l’aide de la syntaxe where.

Vous allez organiser votre code sur deux fichiers :

  • processor.rs : définissez deux traits publics et une fonction générique qui les utilise tous les deux :
    • Summarize : un trait avec une méthode summary qui prend &self et renvoie une String
    • Validate : un trait avec une méthode validate qui prend &self et renvoie un bool
    Créez ensuite une fonction générique publique appelée process_items qui accepte deux paramètres de types génériques différents. Utilisez une clause where pour spécifier que le premier type doit implémenter à la fois Clone et Summarize, tandis que le second type doit implémenter Validate. La fonction doit afficher le résumé du premier élément, puis indiquer si le second élément est valide.
  • main.rs : créez deux structures publiques qui implémentent les traits requis :
    • Article : avec un champ public title (String). Implémentez Summarize pour renvoyer Article: {title}, et dérivez Clone.
    • Form : avec un champ public filled (bool). Implémentez Validate pour renvoyer la valeur de filled.
    Utilisez les entrées fournies pour créer un Article et un Form, puis appelez process_items avec les deux.

La clause where rend la signature de votre fonction beaucoup plus claire que si toutes les contraintes étaient entassées entre les chevrons. Les exigences de chaque type apparaissent sur leur propre ligne, ce qui permet de voir facilement ce dont chaque paramètre générique a besoin.

Votre sortie doit afficher le résumé suivi du résultat de la validation :

Article: {title}
Valid: {true/false}

Par exemple, avec les entrées Rust Tips et true :

Article: Rust Tips
Valid: true

Et avec les entrées Breaking News et false :

Article: Breaking News
Valid: false

Vous recevrez deux entrées : le titre de l’article et si le formulaire est rempli (à analyser comme un bool).

Essayez vous-même

mod processor;

use processor::{Summarize, Validate, process_items};
use std::io;

// TODO: Définir une struct publique Article avec un champ public title (String)
// Dériver Clone pour Article

// TODO: Implémenter Summarize pour Article
// La méthode summary doit retourner "Article: {title}"

// TODO: Définir une struct publique Form avec un champ public filled (bool)

// TODO: Implémenter Validate pour Form
// La méthode validate doit retourner la valeur de filled

fn main() {
    let mut title = String::new();
    io::stdin().read_line(&mut title).expect("Failed to read line");
    let title = title.trim().to_string();

    let mut filled_input = String::new();
    io::stdin().read_line(&mut filled_input).expect("Failed to read line");
    let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");

    // TODO: Créer un Article avec le title donné
    
    // TODO: Créer un Form avec la valeur filled donnée
    
    // TODO: Appeler process_items avec l'article et le form
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur Rust en ligne