Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Séparer les modules dans différents fichiers

Jusqu’à présent, tous les exemples de ce chapitre ont défini plusieurs modules dans un seul fichier. Quand les modules vont grossir, vous allez probablement vouloir déplacer leurs définitions dans un fichier séparé pour faciliter le parcours de votre code.

Prenons par exemple le code de l’encart 7-17 qui avait plusieurs modules de restauration. Nous allons extraire les modules dans des fichiers, au lieu d’avoir tous les modules définis dans le fichier de la crate racine. Dans notre cas, le fichier de la crate racine est src/lib.rs, mais cette procédure fonctionne aussi avec les crates binaires dans lesquelles le fichier de la crate racine est src/main.rs.

Tout d’abord, nous allons extraire le module salle_a_manger vers son propre fichier. Nous enlevons le code entre parenthèses du module salle_a_manger, en ne laissant que la déclaration mod salle_a_manger;, de sorte que src/lib.rs` corresponde au code de l’encart 7-21.

Filename: src/lib.rs
mod front_of_house;

pub use crate::salle_a_manger::accueil;

pub fn manger_au_restaurant() {
    accueil::ajouter_a_la_liste_attente();
}
Listing 7-21: Declaring the front_of_house module whose body will be in src/front_of_house.rs

Ensuite, plaçons le code qui était entre parenthèses dans un nouveau fichier nommé src/front_of_house.rs, comme dans l’encart 7-22. Le compilateur sait qu’il doit lire ce fichier car il a croisé la déclaration de module dans la crate racine avec le nom salle_a_manger.

Filename: src/front_of_house.rs
pub mod accueil {
    pub fn ajouter_a_la_liste_attente() {}
}
Listing 7-22: Definitions inside the front_of_house module in src/front_of_house.rs

Notez que vous devez charger un fichier avec une déclaration mod une seule fois dans votre arborescence de modules. Une fois que le compilateur sait que le fichier fait partie du projet (et qu’il sait où son code réside dans l’arborescence des modules, ce qui dépend d’où vous avez mis l’instruction mod), les autres fichiers de votre projet devraient faire référence au code des fichiers chargés en utilisant un chemin vers l’endroit où il a été déclaré, comme vu dans la section « Désigner un élément dans l’arborescence de modules ». En d’autres termes, mod n’est pas l’équivalent d’un « include » que vous avez pu voir dans d’autres langages.

Ensuite, nous allons extraire le module accueil dans son propre fichier. Le processus est un peu différent, car accueil est un sous-module de salle_a_manger, pas du module racine. Nous mettrons le fichier pour accueil dans un nouveau sous-répertoire qui sera nommé selon ses ancêtres dans l’arborescence des modules, dans ce cas src/salle_a_manger.

Pour commencer à déplacer accueil, nous changeons src/salle_a_mange.rs de manière à ce qu’il ne contienne que la déclaration du module accueil :

Filename: src/front_of_house.rs
pub mod hosting;

Ensuite, nous créons un répertoire src/salle_a_manger et un fichier accueil.rs_ qui contiendra les définitions du module accueil :

Filename: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}

Si, au lieu de cela, nous avions mis hosting.rs dans le répertoire src, le compilateur se serait attendu à ce que le code de hosting.rs se trouve dans un module accueil déclaré dans la crate racine, et comme un sous-module du module salle_a_manger. Les règles du compilateur, qui déterminent quels fichiers vérifier pour le code de quels modules, font en sorte que les répertoires et fichiers correspondent davantage à l’arborescence des modules.

Autres chemins d’accès aux fichiers

Jusqu’ici, nous avons traité des chemins d’accès les plus courants utilisés par le compilateur Rust, mais Rust prend également en charge un style plus ancien de chemin d’accès. Pour un module nommé salle_a_manger déclaré dans la crate racine, le compilateur cherchera le code du module dans :

  • src/salle_a_manger.rs (ce que nous venons de voir)
  • src/salle_a_manger/mod.rs (style plus ancien, chemin toujours supporté)

Pour un module nommé accueil qui est un sous-module de salle_a_manger, le compilateur cherchera le code du module dans :

  • src/salle_a_manger/accueil.rs (what we covered)
  • src/salle_a_manger/accueil/mod.rs (style plus ancien, toujours supporté)

Si vous utilisez les deux styles pour le même module, vous obtiendrez une erreur à la compilation. Il est possible d’utiliser un mélange des deux styles pour différents modules au sein d’un même projet, mais cela peut prêter à confusion pour les personnes qui liront votre projet.

Le principal inconvénient du style qui utilise des fichiers nommés mod.rs est que votre projet peut arriver à de nombreux fichiers nommés mod.rs, ce qui peut prêter à confusion quand les avez ouverts en même temps dans votre éditeur.

Nous avons déplacé le code de chaque module vers un fichier séparé, et l’arborescence des modules reste identique. Les appels aux fonctions de manger_au_restaurant vont continuer à fonctionner sans aucune modification, même si les définitions se retrouvent dans des fichiers différents. Cette technique vous permet de déplacer des modules dans de nouveaux fichiers au fur et à mesure qu’ils s’agrandissent.

Remarquez que l’instruction pub use crate::salle_a_manger::accueil dans src/lib.rs n’a pas changé, et que use n’a aucun impact sur quels fichiers sont compilés pour constituer la crate. Le mot-clé mod déclare un module, et Rust recherche un fichier de code qui porte le nom dudit module.

Résumé

Rust vous permet de découper un paquet en plusieurs crates et une crate en modules afin que vous puissiez réutiliser vos éléments d’un module à un autre. Vous pouvez faire cela en utilisant des chemins absolus ou relatifs. Ces chemins peuvent être importés dans la portée avec l’instruction use pour pouvoir utiliser l’élément plusieurs fois dans la portée avec un chemin plus court. Le code du module est privé par défaut, mais vous pouvez rendre publiques des définitions en ajoutant le mot-clé pub.

Au prochain chapitre, nous allons nous intéresser à quelques collections de structures de données de la bibliothèque standard que vous pourrez utiliser dans votre code soigneusement organisé.