Définir des modules pour gérer la portée et la visibilité
Dans cette section, nous allons aborder les modules et les autres outils du
système de modules, à savoir les chemins qui nous permettent de nommer les
éléments ; l'utilisation du mot-clé use
qui importe un chemin dans la portée ;
et le mot-clé pub
qui rend publics les éléments. Nous verrons aussi le mot-clé
as
, les paquets externes, et l'opérateur glob. Pour commencer, penchons-nous
sur les modules !
Les modules nous permettent de regrouper le code d'une crate pour une meilleure lisibilité et pour la facilité de réutilisation. Les modules permettent aussi de gérer la visibilité des éléments, qui précise si un élément peut être utilisé à l'extérieur du module (c'est public) ou s'il est un constituant interne et n'est pas disponible pour une utilisation externe (c'est privé).
Voici un exemple : écrivons une crate de bibliothèque qui permet de simuler un restaurant. Nous allons définir les signatures des fonctions mais nous allons laisser leurs corps vides pour nous concentrer sur l'organisation du code, plutôt que de coder pour de vrai un restaurant.
Dans le secteur de la restauration, certaines parties d'un restaurant sont assimilées à la salle à manger et d'autres aux cuisines. La partie salle à manger est l'endroit où se trouvent les clients ; c'est l'endroit où les hôtes installent les clients, où les serveurs prennent les commandes et encaissent les clients, et où les barmans préparent des boissons. Dans la partie cuisines, nous retrouvons les chefs et les cuisiniers qui travaillent dans la cuisine, mais aussi les plongeurs qui nettoient la vaisselle et les gestionnaires qui s'occupent des tâches administratives.
Pour organiser notre crate de la même manière qu'un vrai restaurant, nous
pouvons organiser les fonctions avec des modules imbriqués. Créez une nouvelle
bibliothèque qui s'appelle restaurant
en utilisant
cargo new --lib restaurant
; puis écrivez le code de l'encart 7-1 dans
src/lib.rs afin de définir quelques modules et quelques signatures de
fonctions.
Fichier : src/lib.rs
mod salle_a_manger {
mod accueil {
fn ajouter_a_la_liste_attente() {}
fn installer_a_une_table() {}
}
mod service {
fn prendre_commande() {}
fn servir_commande() {}
fn encaisser() {}
}
}
Nous définissons un module en commençant avec le mot-clé mod
et nous précisons
ensuite le nom du module (dans notre cas, salle_a_manger
) et nous ajoutons des
accolades autour du corps du module. Dans les modules, nous pouvons avoir
d'autres modules, comme dans notre cas avec les modules accueil
et service
.
Les modules peuvent aussi contenir des définitions pour d'autres éléments, comme
des structures, des énumérations, des constantes, des traits, ou des fonctions
(comme c'est le cas dans l'encart 7-1).
Grâce aux modules, nous pouvons regrouper ensemble des définitions qui sont liées et donner un nom à ce lien. Les développeurs qui utiliseront ce code pourront plus facilement trouver les définitions dont ils ont besoin car ils peuvent parcourir le code en fonction des groupes plutôt que d'avoir à lire toutes les définitions. Les développeurs qui veulent rajouter des nouvelles fonctionnalités à ce code sauront maintenant où placer le code tout en gardant le programme organisé.
Précédemment, nous avons dit que src/main.rs et src/lib.rs étaient des
racines de crates. Nous les appelons ainsi car le contenu de chacun de ces
deux fichiers constituent un module qui s'appelle crate
à la racine de
l'arborescence du module.
L'encart 7-2 présente l'arborescence du module pour la structure de l'encart 7-1.
crate
└── salle_a_manger
├── accueil
│ ├── ajouter_a_la_liste_attente
│ └── installer_a_une_table
└── service
├── prendre_commande
├── servir_commande
└── encaisser
Cette arborescence montre comment les modules sont imbriqués entre eux (par
exemple, accueil
est imbriqué dans salle_a_manger
). L'arborescence montre
aussi que certains modules sont les frères d'autres modules, ce qui veut dire
qu'ils sont définis dans le même module (accueil
et service
sont définis
dans salle_a_manger
). Pour prolonger la métaphore familiale, si le module A
est contenu dans le module B, on dit que le module A est l'enfant du module B
et que ce module B est le parent du module A. Notez aussi que le module
implicite nommé crate
est le parent de toute cette arborescence.
L'arborescence des modules peut rappeler les dossiers du système de fichiers de votre ordinateur ; et c'est une excellente comparaison ! Comme les dossiers dans un système de fichiers, vous utilisez les modules pour organiser votre code. Et comme pour les fichiers dans un dossier, nous avons besoin d'un moyen de trouver nos modules.