Introduction
À mesure qu’un programme Rust grandit, regrouper tous les types et toutes les fonctions dans un seul fichier rend leurs responsabilités plus difficiles à distinguer. Vous avez déjà découvert une bibliothèque et un binaire dans le Lab CLI, ainsi qu’un module de test dans le Lab consacré aux tests. Ce Lab relie maintenant ces exemples préparés au sein d’un même modèle : un package est le projet que Cargo construit, les crates sont des unités de compilation et les modules organisent les noms au sein d’une crate.
Vous allez organiser un petit package de génération de rapports sur le contenu d’un garde-manger. Les fichiers et la majeure partie du code d’implémentation sont déjà préparés. Chaque étape se concentre donc sur une limite particulière : partager un élément depuis la crate de bibliothèque, déclarer un module défini dans un fichier et importer une petite API publique dans la crate binaire.
Partager une fonction entre des crates
Dans cette étape, vous allez identifier les deux crates du package et rendre une fonction de la bibliothèque accessible au binaire.
Placez-vous dans le package Cargo préparé :
cd /home/labex/project/pantry-report
Cargo.toml décrit un package nommé pantry-report. Cargo reconnaît src/lib.rs comme la racine d’une crate de bibliothèque et src/main.rs comme la racine d’une crate binaire. Ces deux crates appartiennent au même package, mais elles sont compilées séparément.
Examinez les racines de crate, qui sont courtes. Les commandes sed -n affichent les plages de lignes demandées sans modifier les fichiers :
sed -n '1,120p' src/lib.rs
sed -n '1,120p' src/main.rs
Le binaire importe report_title en utilisant le chemin de la crate de bibliothèque. En Rust, un nom de package contenant un trait d’union devient un nom de crate contenant un caractère de soulignement dans le code source. Ainsi, pantry-report devient pantry_report.
Le type de retour préparé, &'static str, désigne une chaîne littérale empruntée qui reste valide pendant toute la durée du programme. Le marqueur 'static est une annotation de durée de vie. Les règles explicites concernant les durées de vie dépassent volontairement le cadre de ce cours pour débutants ; aucune modification demandée dans ce Lab ne nécessite de comprendre ou d’écrire une telle annotation.
Les éléments sont privés dans leur module, sauf s’ils sont marqués avec pub. Ouvrez la racine de la bibliothèque :
nano src/lib.rs
Modifiez uniquement la déclaration de la fonction, en remplaçant :
fn report_title() -> &'static str {
par :
pub fn report_title() -> &'static str {
pub ajoute la fonction à l’interface publique de la crate de bibliothèque. Enregistrez avec Ctrl+O, appuyez sur Entrée, puis quittez avec Ctrl+X.
Utilisez cargo check pour vérifier les types des deux crates sans produire une compilation finale exécutable :
cargo check
Exécutez ensuite la crate binaire :
cargo run --quiet
La sortie est :
Pantry Report
Cela prouve que le binaire peut franchir la limite entre les crates et appeler la fonction publique de la bibliothèque.
Déclarer un module défini dans un fichier
Dans cette étape, vous allez relier le fichier préparé inventory.rs à l’arborescence des modules de la crate de bibliothèque.
Un fichier source Rust n’est pas compilé simplement parce qu’il existe. La racine de la crate doit déclarer son module. Pour une déclaration nommée inventory, Rust recherche src/inventory.rs et place ses éléments sous le chemin inventory::....
Examinez le fichier de module préparé. Comme précédemment, sed -n '1,200p' utilise -n pour désactiver l’affichage automatique et 1,200p pour n’afficher que la plage de lignes demandée :
sed -n '1,200p' src/inventory.rs
La ligne #[derive(Debug)] demande à Rust de générer la prise en charge standard du formatage de débogage pour Item. Le programme visible ne dépend pas de cette fonctionnalité ; considérez-la donc comme des métadonnées déjà préparées et non comme une nouvelle exigence. Le type Item, ses champs et describe sont publics. L’auxiliaire availability ne comporte pas de pub ; il reste donc privé à l’intérieur du module. describe peut appeler cet auxiliaire privé, tandis que les appelants externes ne reçoivent que le résultat public.
Ouvrez la racine de la bibliothèque :
nano src/lib.rs
Remplacez // MODULE_DECLARATION par :
pub mod inventory;
Le premier pub expose le module à travers la crate de bibliothèque. La partie mod inventory; rattache le fichier à l’arborescence des modules. Enregistrez et quittez Nano, puis vérifiez le package :
cargo check
Finished `dev` profile ...
La vérification réussie prouve que Rust a trouvé src/inventory.rs et l’a compilé comme pantry_report::inventory.
Importer et utiliser l’API publique
Dans cette étape, vous allez utiliser une déclaration use pour importer des éléments du module dans la crate binaire et afficher un relevé du garde-manger.
Sans importation, les chemins complets sont pantry_report::inventory::Item et pantry_report::inventory::describe. Une déclaration use crée des noms plus courts dans la portée actuelle, sans déplacer ni copier les éléments.
Ouvrez le code source du binaire :
nano src/main.rs
Remplacez // INVENTORY_IMPORT par cet import groupé :
use pantry_report::inventory::{describe, Item};
Les accolades regroupent deux éléments qui partagent le même préfixe de chemin. Remplacez ensuite // INVENTORY_REPORT par :
let lentils = Item {
name: String::from("lentils"),
quantity: 4,
};
println!("{}", describe(&lentils));
Le binaire peut construire un Item, car le type et ses deux champs sont publics. Il emprunte l’élément pour appeler describe ; cette fonction publique appelle en privé availability dans son propre module.
Enregistrez et quittez Nano, puis exécutez le package :
cargo run --quiet
Pantry Report
lentils: 4 jars (stocked)
Ces deux lignes montrent que le partage entre les crates et l’organisation en modules fonctionnent tous deux au moyen d’une petite API publique.
Résumé
Vous avez travaillé avec un package Cargo contenant une crate de bibliothèque et une crate binaire, rendu un élément de la bibliothèque public, déclaré un module défini dans un fichier, suivi les chemins des crates et des modules, raccourci ces chemins avec use et conservé un auxiliaire d’implémentation privé derrière une petite API publique.


