Séparer les modules dans différents fichiers
Jusqu’à présent, tous les exemples de ce chapitre définissaient plusieurs modules dans un seul fichier. Lorsque les modules deviennent volumineux, vous pourriez vouloir déplacer leurs définitions dans un fichier séparé pour rendre le code plus facile à naviguer.
Par exemple, partons du code du listing 7-17 qui avait plusieurs modules de restaurant. Nous allons extraire les modules dans des fichiers au lieu d’avoir tous les modules définis dans le fichier racine de la crate. Dans ce cas, le fichier racine de la crate est src/lib.rs, mais cette procédure fonctionne aussi avec les crates binaires dont le fichier racine est src/main.rs.
Tout d’abord, nous allons extraire le module front_of_house dans son propre fichier. Supprimez le code à l’intérieur des accolades du module front_of_house, en ne laissant que la déclaration mod front_of_house;, de sorte que src/lib.rs contienne le code montré dans le listing 7-21. Notez que cela ne compilera pas tant que nous n’aurons pas créé le fichier src/front_of_house.rs dans le listing 7-22.
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
front_of_house module whose body will be in src/front_of_house.rsEnsuite, placez le code qui se trouvait entre les accolades dans un nouveau fichier nommé src/front_of_house.rs, comme montré dans le listing 7-22. Le compilateur sait qu’il doit chercher dans ce fichier car il a rencontré la déclaration de module dans la racine de la crate avec le nom front_of_house.
pub mod hosting {
pub fn add_to_waitlist() {}
}
front_of_house module in src/front_of_house.rsNotez que vous n’avez besoin de charger un fichier avec une déclaration mod qu’une seule fois dans votre arbre de modules. Une fois que le compilateur sait que le fichier fait partie du projet (et sait où dans l’arbre de modules le code réside grâce à l’endroit où vous avez placé l’instruction mod), les autres fichiers de votre projet doivent faire référence au code du fichier chargé en utilisant un chemin vers l’endroit où il a été déclaré, comme couvert dans la section [« Les chemins pour faire référence à un élément dans l’arbre de modules »][paths]. En d’autres termes, mod n’est pas une opération « include » que vous avez peut-être vue dans d’autres langages de programmation.
Ensuite, nous allons extraire le module hosting dans son propre fichier. Le processus est un peu différent car hosting est un module enfant de front_of_house, et non du module racine. Nous placerons le fichier pour hosting dans un nouveau répertoire qui sera nommé d’après ses ancêtres dans l’arbre de modules, dans ce cas src/front_of_house.
Pour commencer à déplacer hosting, nous modifions src/front_of_house.rs pour qu’il ne contienne que la déclaration du module hosting :
pub mod hosting;
Ensuite, nous créons un répertoire src/front_of_house et un fichier hosting.rs pour contenir les définitions faites dans le module hosting :
pub fn add_to_waitlist() {}
Si au contraire nous placions hosting.rs dans le répertoire src, le compilateur s’attendrait à ce que le code de hosting.rs soit dans un module hosting déclaré à la racine de la crate et non déclaré comme enfant du module front_of_house. Les règles du compilateur concernant les fichiers à vérifier pour le code de chaque module font que les répertoires et les fichiers correspondent plus étroitement à l’arbre de modules.
Chemins de fichiers alternatifs
Jusqu’ici, nous avons couvert les chemins de fichiers les plus idiomatiques que le compilateur Rust utilise, mais Rust prend aussi en charge un ancien style de chemin de fichier. Pour un module nommé front_of_house déclaré à la racine de la crate, le compilateur cherchera le code du module dans :
- src/front_of_house.rs (ce que nous avons couvert)
- src/front_of_house/mod.rs (ancien style, chemin toujours pris en charge)
Pour un module nommé hosting qui est un sous-module de front_of_house, le compilateur cherchera le code du module dans :
- src/front_of_house/hosting.rs (ce que nous avons couvert)
- src/front_of_house/hosting/mod.rs (ancien style, chemin toujours pris en charge)
Si vous utilisez les deux styles pour le même module, vous obtiendrez une erreur de compilation. Utiliser un mélange des deux styles pour différents modules dans le même projet est autorisé mais pourrait être déroutant pour les personnes naviguant dans votre projet.
Le principal inconvénient du style utilisant des fichiers nommés mod.rs est que votre projet peut se retrouver avec de nombreux fichiers nommés mod.rs, ce qui peut prêter à confusion lorsque vous les avez ouverts en même temps dans votre éditeur.
Nous avons déplacé le code de chaque module dans un fichier séparé, et l’arbre de modules reste le même. Les appels de fonction dans eat_at_restaurant fonctionneront sans aucune modification, même si les définitions se trouvent dans des fichiers différents. Cette technique vous permet de déplacer les modules vers de nouveaux fichiers à mesure qu’ils grandissent en taille.
Notez que l’instruction pub use crate::front_of_house::hosting dans src/lib.rs n’a pas changé non plus, et use n’à aucun impact sur les fichiers qui sont compilés en tant que partie de la crate. Le mot-clé mod déclare les modules, et Rust cherche dans un fichier portant le même nom que le module le code qui va dans ce module.
Résumé
Rust vous permet de diviser un package en plusieurs crates et une crate en modules afin que vous puissiez faire référence à des éléments définis dans un module depuis un autre module. Vous pouvez le faire en spécifiant des chemins absolus ou relatifs. Ces chemins peuvent être amenés dans la portée avec une instruction use afin que vous puissiez utiliser un chemin plus court pour plusieurs utilisations de l’élément dans cette portée. Le code des modules est privé par défaut, mais vous pouvez rendre les définitions publiques en ajoutant le mot-clé pub.
Dans le prochain chapitre, nous examinerons quelques structures de données de collections dans la bibliothèque standard que vous pouvez utiliser dans votre code bien organisé.