Expliquer chaque résultat de vérification de l’équipement

RustBeginner
Pratiquer maintenant

Introduction

Une liste d’éléments fiable constitue le début de la vérification de l’équipement. L’équipe a besoin d’une explication pour chaque type : combien d’éléments sont en bon état, lesquels sont endommagés, ce qui manque et ce qui dépasse le plan. Un objet non planifié ou un besoin nul ne rend pas l’entrée invalide.

Dans ce laboratoire, vous implémenterez cette logique de vérification et lirez son rapport avec deux ensembles différents de fichiers réels. L’environnement est indépendant : l’analyseur d’états et le collecteur d’identités du laboratoire précédent sont déjà fournis. Aucun fichier de sa VM n’est nécessaire. Vous devez connaître ses règles d’identité et de conflit, ainsi que les structures, énumérations, HashMap, Result, lectures de fichiers et boucles Rust. L’auteur estime la durée à 45 minutes, lecture et corrections ordinaires comprises ; ce n’est pas une durée de réalisation mesurée auprès de débutants.

Vérifier chaque type et chaque élément

Dans cette étape, construisez la vérification en trois modifications : identifier les types concernés, collecter leurs ensembles complets d’objets, puis calculer les manques et les surplus. Ouvrez Terminal. Ajoutez Cargo au chemin de recherche de ce shell et entrez dans le projet préparé indépendamment. Répétez l’export dans un nouveau terminal et cd si vous perdez votre emplacement :

export PATH=/home/labex/.cargo/bin:$PATH
cd /home/labex/project/field-kit

Examinez d’abord un résultat normal qui fonctionne déjà. L’analyseur d’états et le collecteur d’identités sont fournis dans ce laboratoire :

cat data/plan.tsv
cargo run --quiet -- assets data/scans.tsv

La table comporte six ID physiques, pas sept scans. a, b et c sont des objets light-a en bon état. d est un light-b endommagé ; e et f sont des objets en bon état et endommagé du type non planifié other. Le nom affiché Flashlight appartient à deux ID de type planifiés différents. Le plan exige aussi deux cordes sans scans et zéro pièce de rechange sans scans. Conservez ces distinctions pour décider ce qu’un rapport complet doit expliquer.

Modifiez uniquement src/readiness.rs, en conservant le nom public de sa fonction et les types des paramètres et du retour. Gardez les autres fichiers sources, Cargo.toml, rust-toolchain.toml et chaque fichier original de data/ inchangés. Vous créerez des entrées expérimentales séparées dans le répertoire du projet. L’interface de commandes lit les chemins réels que vous indiquez ; elle ne leur substitue pas un exemple.

Le contrat TSV contrôlé reste le même : les en-têtes exacts de trois champs sont type_id, name, required pour les plans et asset_id, type_id, condition pour les scans, avec de vraies tabulations entre les champs. Les ID commencent par une lettre ASCII minuscule, suivie de minuscules, de chiffres ou de -. Les noms du plan sont des textes ASCII imprimables non vides, espaces compris. Les quantités sont des chiffres décimaux de valeur 0–999, avec des zéros initiaux autorisés. Les ID de type du plan ne peuvent pas se répéter, mais les noms affichés le peuvent. Les états sont exactement good ou damaged. LF/CRLF, l’absence de saut final et les lignes suivantes entièrement vides sont acceptés. Les espaces aux extrémités des champs ne sont pas supprimés ; les lignes ne contenant que des espaces blancs ne sont pas vides, et les retours chariot isolés ne sont pas des fins de ligne. Ce sont des enregistrements textuels synthétiques, pas des inspections physiques.

Lisez les types fournis et la fonction incomplète :

cat src/lib.rs
cat src/readiness.rs

Need contient l’ID de type, le nom et la quantité requise du plan. Scan contient un ID d’objet, un ID de type, un état et une ligne diagnostique. reconcile reçoit &[Need] et &[Scan], des tranches empruntées qu’il ne doit pas modifier. Les objets ont déjà passé la validation de format et la collecte par identité ; chaque ID physique apparaît donc une seule fois. Le Vec<TypeSummary> renvoyé doit inclure l’union des types planifiés et scannés, les ensembles complets d’ID en bon état et endommagés, la quantité requise, le manque et le surplus. Le formateur préparé fournit les noms affichés, trie les lignes et listes d’ID et affiche la relation planned ou unplanned de chaque objet.

Première modification : conserver les types concernés

Considérez un plan sans aucun objet scanné. Un besoin positif constitue toujours un manque, tandis qu’un besoin nul donne un manque nul. Créez une entrée de scans vide séparée ; ne videz pas l’original protégé. printf affiche sa chaîne de format en interprétant \t comme une tabulation et \n comme un retour à la ligne. Les apostrophes conservent ces barres obliques inverses pour printf, et > écrit ce fichier expérimental nommé. Son en-tête est sa seule ligne :

printf 'asset_id\ttype_id\tcondition\n' > empty-scans.tsv
cat empty-scans.tsv

Avant de modifier le code, prédisez les types que cette entrée doit conserver : light-a, light-b, rope et zero, avec les besoins 2, 1, 2 et 0. Aucun type provenant uniquement des scans n’existe dans cette entrée précise. La fonction générale doit néanmoins découvrir les types des deux tranches afin que les scans réels puissent ensuite ajouter other.

Créez un point de sauvegarde limité au source. mktemp -d crée un nouveau répertoire en remplaçant les six caractères X par un suffixe unique ; il ne réutilise pas une sauvegarde précédente. $() capture le chemin affiché dans la variable de session. && n’exécute cp -p que si la création du répertoire réussit. La copie conserve les métadonnées du source et les guillemets autour de la variable gardent son chemin groupé. Si l’une des opérations échoue, lisez l’erreur et obtenez une sauvegarde avant de modifier :

rs03_before_types=$(mktemp -d .edit-before-types.XXXXXX) && cp -p src/readiness.rs "$rs03_before_types/readiness.rs"

Ouvrez le fichier existant avec nano ; -c affiche la position du curseur :

nano -c src/readiness.rs

Nano utilise ^ pour Ctrl. Appuyez sur Ctrl+W, recherchez pub fn reconcile, puis appuyez sur Entrée. Lisez les accolades ouvrante et fermante de cette fonction. Utilisez les flèches et Retour arrière/Suppr pour modifier uniquement son corps et les liaisons des paramètres inutilisés. Renommez _needs et _assets en needs et assets, en conservant leurs types. Gardez l’import fourni use crate::{Need, Scan, TypeSummary}; ; cette phase n’utilise pas encore Condition.

Construisez cette première phase à partir des relations entre données. Créez un vecteur types vide. Ajoutez chaque ID de type planifié. Parcourez ensuite les objets et ajoutez un ID de type uniquement si types.contains(&asset.type_id) est faux. Les ID de type du plan sont déjà uniques. .clone() copie une chaîne d’ID de type possédée depuis un enregistrement emprunté afin que votre résultat puisse la posséder.

Créez ensuite un vecteur summaries vide et parcourez chaque ID de type collecté. Initialisez sa quantité requise à zéro, puis recherchez ce type dans le plan. usize::from(need.required) convertit la valeur u16 du plan vers le type de comptage utilisé par les longueurs de vecteur. Utilisez pour l’instant des vecteurs good_ids et damaged_ids vides. Tant qu’aucun objet utilisable n’a été compté, affectez required à missing et mettez surplus à zéro. Ajoutez un TypeSummary avec ces variables et faites de summaries l’expression finale de la fonction. La notation abrégée de champ comme type_id, required utilise des variables portant les mêmes noms. Vous n’avez pas encore implémenté la classification des objets.

Enregistrez avec Ctrl+O, Entrée pour confirmer le nom courant, puis Ctrl+X pour quitter. Lisez la fonction enregistrée avant de l’exécuter :

cat src/readiness.rs

cargo run compile et exécute le programme ; --quiet masque la progression de Cargo et -- transmet les arguments suivants au programme. Testez le cas limité sans scans :

cargo run --quiet -- check data/plan.tsv empty-scans.tsv

Vous devez obtenir les quatre types planifiés, zéro objet en bon état et des ensembles d’ID vides, des manques de 2, 1, 2 et 0 et zéro surplus. Aucune ligne de données d’objet ne doit suivre l’en-tête ASSET. Cette première phase est correcte uniquement pour cette observation sans scans. Ce n’est pas une implémentation complète pour une liste d’objets non vide. N’interprétez pas un code de sortie nul comme la preuve que toutes les règles de vérification sont terminées.

Deuxième modification : conserver les ensembles complets par état

Prédisez maintenant les ensembles complets des scans réels : light-a a les ID en bon état a,b,c ; light-b a l’ID endommagé d ; other a l’ID en bon état e et l’ID endommagé f. rope et zero ont toujours besoin de leur propre résumé même sans objets. Gardez chaque ensemble au lieu de choisir un objet « en trop » préféré.

Préservez votre phase fonctionnelle d’union des types :

rs03_before_sets=$(mktemp -d .edit-before-sets.XXXXXX) && cp -p src/readiness.rs "$rs03_before_sets/readiness.rs"
nano -c src/readiness.rs

En haut du fichier, modifiez l’import de la bibliothèque pour inclure l’énumération que vous utilisez maintenant :

use crate::{Condition, Need, Scan, TypeSummary};

C’est une modification explicite du source : le code initial n’importe pas Condition. crate désigne cette bibliothèque ; use rend ses noms disponibles dans ce module. Ajouter l’import au moment de sa première utilisation évite aussi un avertissement d’import inutilisé dans la phase précédente.

Recherchez pub fn reconcile. Gardez la logique d’union des types et de quantité requise. Rendez good_ids et damaged_ids modifiables, car vous allez y ajouter des ID. Dans la boucle de chaque type, parcourez tous les objets, sélectionnez ceux ayant le type_id courant et faites une correspondance sur leur état. Pour la variante Good, ajoutez un clone de l’ID d’objet au vecteur des objets en bon état ; pour Damaged, ajoutez-le au vecteur des objets endommagés. Les deux variantes sont des entrées valides. Ne supprimez pas les objets endommagés ou non planifiés. Laissez les deux affectations temporaires de manque et de surplus inchangées jusqu’à la prochaine modification.

Enregistrez, quittez et exécutez avec les scans réels :

cargo run --quiet -- check data/plan.tsv data/scans.tsv

Lisez les ID de type, les quantités requises, les nombres d’objets en bon état, les ensembles complets d’ID et les lignes ASSET. Ils doivent correspondre à votre prédiction, avec other inclus. Les colonnes de manque et de surplus sont encore temporaires et ne sont pas des résultats généraux valides. Par exemple, le manque temporaire de light-a peut encore afficher 2 alors que ses trois ID en bon état sont maintenant présents. Expliquez pourquoi cela ne peut pas être un rapport terminé. Vous corrigerez ensuite ces deux calculs ; ne prétendez pas que cette table intermédiaire passe la vérification finale.

Troisième modification : calculer les manques et surplus avec les seuls objets en bon état

Seuls les objets uniques en bon état satisfont la demande. Pour light-a, un besoin de 2 et 3 objets en bon état donnent un manque nul et un surplus de 1. Pour light-b, son objet endommagé ne satisfait pas le besoin : manque de 1, surplus nul. Il manque 2 objets pour rope. zero reste à 0/0. Le type non planifié other a un besoin nul et un objet en bon état, donc un surplus de 1 ; son ID endommagé est conservé mais n’ajoute rien au surplus.

Sauvegardez la phase qui collecte déjà les ensembles corrects :

rs03_before_totals=$(mktemp -d .edit-before-totals.XXXXXX) && cp -p src/readiness.rs "$rs03_before_totals/readiness.rs"
nano -c src/readiness.rs

Recherchez pub fn reconcile, puis remplacez uniquement les expressions temporaires de manque et de surplus. Le len() d’un vecteur donne son nombre d’éléments. saturating_sub soustrait sans passer sous zéro, évitant le débordement inférieur d’un entier non signé. Les règles sont missing = max(required - good, 0) et surplus = max(good - required, 0) ; appliquez-les à good_ids.len(), jamais au nombre de scans bruts ou d’ID endommagés. Gardez intacts l’union des types et les vecteurs complets. Enregistrez avec Ctrl+O, Entrée, puis Ctrl+X.

cargo run --quiet -- check data/plan.tsv data/scans.tsv
TYPE	type_id	name	required	good	missing	surplus	good_ids	damaged_ids
TYPE	light-a	Flashlight	2	3	0	1	a,b,c	-
TYPE	light-b	Flashlight	1	0	1	0	-	d
TYPE	other	-	0	1	0	1	e	f
TYPE	rope	Rope	2	0	2	0	-	-
TYPE	zero	Spare	0	0	0	0	-	-
ASSET	asset_id	type_id	condition	plan
ASSET	a	light-a	good	planned
ASSET	b	light-a	good	planned
ASSET	c	light-a	good	planned
ASSET	d	light-b	damaged	planned
ASSET	e	other	good	unplanned
ASSET	f	other	damaged	unplanned

Chaque quantité est maintenant traçable : light-b conserve l’ID endommagé d mais présente un manque ; other conserve ses deux ID, mais seul e crée un surplus. Le scan répété de a n’a jamais créé un autre objet physique. Répétez le test précédent avec la source vide et la fonction terminée :

cargo run --quiet -- check data/plan.tsv empty-scans.tsv

Ses quatre types planifiés et ses manques sans scans doivent toujours être corrects. C’est seulement maintenant que la vérification complète de cette étape doit réussir. Des ordres de collecte internes équivalents restent valides, car le formateur préparé trie les lignes affichées et les listes d’ID.

Réparer une modification du source sans réinitialiser le projet

L’erreur de Cargo nomme un fichier et une ligne. Rouvrez ce fichier, trouvez la fonction avec Ctrl+W et réparez la modification indiquée. Si une modification accidentelle n’a pas été enregistrée, Ctrl+X, puis N à la question d’enregistrement l’abandonne ; cela n’annule pas une modification enregistrée auparavant.

Uniquement pour récupérer une erreur enregistrée, choisissez le point de sauvegarde de la phase à refaire : .edit-before-types.* contient le code initial, .edit-before-sets.* contient la phase d’union des types et .edit-before-totals.* contient les ensembles complets d’ID avant les calculs finaux. Dans un nouveau Terminal, répétez PATH et cd, puis énumérez les noms réels des sauvegardes :

ls -d .edit-before-*

-d énumère les noms des répertoires plutôt que leur contenu et * correspond aux suffixes générés. Exécutez la commande suivante ; pendant que le shell attend, collez un nom de répertoire exact parmi ceux affichés et appuyez sur Entrée. read stocke votre sélection dans cette variable de session :

read rs03_restore

Confirmez le source sélectionné avant de le copier :

cat "$rs03_restore/readiness.rs"

Si le chemin ou la phase est incorrect, répétez la sélection et l’inspection. Sans sauvegarde correspondante, réparez la fonction à l’aide de sa référence plutôt que de deviner un chemin. Après avoir confirmé la phase voulue, cette commande remplace délibérément uniquement le source readiness autorisé :

cp -p "$rs03_restore/readiness.rs" src/readiness.rs

Refaites ensuite les modifications et tests concernés ; un point de sauvegarde du source ne change pas vos entrées. Ne modifiez jamais le plan original pour l’adapter à un algorithme incorrect. La référence ci-dessous sert à comparer une partie précise après votre tentative, pas à remplacer le fichier entier par défaut.

Référence complète de vérification pour comparaison et récupération
use crate::{Condition, Need, Scan, TypeSummary};

pub fn reconcile(needs: &[Need], assets: &[Scan]) -> Vec<TypeSummary> {
    let mut types = Vec::new();
    for need in needs {
        types.push(need.type_id.clone());
    }
    for asset in assets {
        if !types.contains(&asset.type_id) {
            types.push(asset.type_id.clone());
        }
    }
    let mut summaries = Vec::new();
    for type_id in types {
        let mut required = 0;
        for need in needs {
            if need.type_id == type_id {
                required = usize::from(need.required);
            }
        }
        let mut good_ids = Vec::new();
        let mut damaged_ids = Vec::new();
        for asset in assets {
            if asset.type_id == type_id {
                match asset.condition {
                    Condition::Good => good_ids.push(asset.asset_id.clone()),
                    Condition::Damaged => damaged_ids.push(asset.asset_id.clone()),
                }
            }
        }
        let missing = required.saturating_sub(good_ids.len());
        let surplus = good_ids.len().saturating_sub(required);
        summaries.push(TypeSummary {
            type_id, required, good_ids, damaged_ids, missing, surplus,
        });
    }
    summaries
}

Expliquer une couverture partielle depuis une autre source

Dans cette étape, vous utiliserez d’autres chemins d’entrée pour examiner des manques partiels et un type non planifié représenté uniquement par du matériel endommagé. Continuez dans Terminal, dans /home/labex/project/field-kit. Préservez tous les fichiers originaux de data/ ; créez plutôt les deux fichiers d’essai séparés ci-dessous.

Les courts blocs d’entrée ci-dessous utilisent un here-document. cat reçoit les lignes suivantes comme entrée, > écrit le fichier expérimental nommé et <<'TSV' commence une entrée littérale jusqu’à une ligne contenant uniquement TSV. Le délimiteur entre apostrophes empêche le développement du contenu par le shell. Copiez les deux lignes de délimitation et conservez les vraies tabulations. Ce sont de petites entrées de test, pas des remplacements d’un module Rust. Le nom Water filter contient un espace dans un seul champ ; les tabulations séparent les champs.

cat > trial-plan.tsv <<'TSV'
type_id	name	required
lamp	Lamp	2
filter	Water filter	5
zero	Spare	0
TSV
cat > trial-scans.tsv <<'TSV'
asset_id	type_id	condition
l-one	lamp	good
l-two	lamp	damaged
f-one	filter	good
f-two	filter	good
u-one	unplanned	damaged
TSV

Avant d’exécuter, prédisez le manque de lampes, le manque de filtres et si le type non planifié uniquement endommagé restera présent. Indiquez maintenant ces fichiers réels :

cargo run --quiet -- check trial-plan.tsv trial-scans.tsv
TYPE	type_id	name	required	good	missing	surplus	good_ids	damaged_ids
TYPE	filter	Water filter	5	2	3	0	f-one,f-two	-
TYPE	lamp	Lamp	2	1	1	0	l-one	l-two
TYPE	unplanned	-	0	0	0	0	-	u-one
TYPE	zero	Spare	0	0	0	0	-	-
ASSET	asset_id	type_id	condition	plan
ASSET	f-one	filter	good	planned
ASSET	f-two	filter	good	planned
ASSET	l-one	lamp	good	planned
ASSET	l-two	lamp	damaged	planned
ASSET	u-one	unplanned	damaged	unplanned

Avant d’interpréter le rapport, prédisez les manques de lampes et de filtres à partir des objets en bon état, pas du nombre de scans. Il manque une lampe malgré deux lignes de scan. Deux filtres utilisables ne satisfont que deux des cinq requis : il en manque trois. L’objet non planifié endommagé reste visible, avec zéro objet en bon état et zéro surplus. zero reste présent même si aucun scan d’essai ne le mentionne.

Essayez une modification contrôlée sans modifier ni les données originales ni vos premiers scans d’essai. cp -p crée une copie en conservant les métadonnées du fichier copié. Utilisez ce nouveau nom de fichier séparé ; si vous l’avez déjà utilisé lors d’une tentative précédente, préservez ce travail ou choisissez un autre nom inutilisé et utilisez-le de façon cohérente dans les commandes suivantes.

cp -p trial-scans.tsv trial-scans-one-repair.tsv
nano -c trial-scans-one-repair.tsv

Appuyez sur Ctrl+W, recherchez l-two et appuyez sur Entrée. Sur cette ligne uniquement, remplacez le mot d’état damaged par good, avec les flèches et Retour arrière/Suppr. Conservez son ID d’objet, son ID de type, l’en-tête et les vraies tabulations séparatrices. Enregistrez avec Ctrl+O, Entrée, puis quittez avec Ctrl+X. C’est une modification intentionnelle de votre expérience séparée, pas une réparation de preuves protégées.

Prédisez les deux lignes du rapport concernées avant d’exécuter : TYPE lamp doit maintenant avoir deux ID en bon état, aucun ID endommagé, zéro manque et zéro surplus. ASSET l-two doit passer à l’état good tout en restant planifié. Toutes les autres lignes de type et d’objet doivent rester inchangées ; les besoins en filtres et l’objet non planifié endommagé n’ont pas changé.

cargo run --quiet -- check trial-plan.tsv trial-scans-one-repair.tsv

Lisez ces deux lignes et confirmez que les autres correspondent toujours. Si davantage de choses ont changé, examinez votre copie avec cat et corrigez le champ modifié involontairement ; ne changez pas l’algorithme simplement pour l’adapter à une modification accidentelle de l’entrée. Revenez à votre première source d’essai inchangée :

cargo run --quiet -- check trial-plan.tsv trial-scans.tsv

Le manque de lampes doit revenir à un, avec l-two endommagé. Les deux rapports diffèrent parce que leurs entrées réellement nommées diffèrent ; aucune source n’est remplacée silencieusement. La même implémentation terminée de vérification doit expliquer les deux cas.

Une erreur d’entrée ne doit pas devenir un rapport de manque ni provoquer un retour silencieux à l’exemple original. Le mauvais nom de fichier suivant est intentionnel et doit renvoyer un état non nul :

cargo run --quiet -- check trial-plans.tsv trial-scans.tsv

L’erreur nomme le fichier inexistant trial-plans.tsv. Corrigez le pluriel ajouté par erreur et relancez :

cargo run --quiet -- check trial-plan.tsv trial-scans.tsv

Pour provoquer une erreur de format, utilisez l’exemple existant d’état inconnu. Cette commande doit aussi renvoyer un état non nul et mentionner data/bad-status.tsv ainsi que sa ligne :

cargo run --quiet -- check trial-plan.tsv data/bad-status.tsv

broken est un mot invalide, tandis que damaged est un état valide qui ne satisfait pas la demande. Reprenez en sélectionnant les scans d’essai valides :

cargo run --quiet -- check trial-plan.tsv trial-scans.tsv

Enfin, revenez aux entrées originales :

cargo run --quiet -- check data/plan.tsv data/scans.tsv

Le rapport original revient, car le programme lit les chemins réels, et non un rapport en cache ou un indicateur de préparation codé en dur. Les fichiers originaux et d’essai sont tous intacts. Vous pouvez examiner chacun avec cat ; pour reprendre après une modification accidentelle d’un fichier d’essai, répétez son bloc complet de création ci-dessus. Les originaux protégés ne servent pas à réparer une erreur de code.

Résumé

Vous avez implémenté la vérification complète des types à partir d’un plan et d’enregistrements physiques uniques. Seuls les éléments en bon état ont satisfait les besoins ; une couverture partielle a laissé un manque, et les éléments endommagés comme les surplus sont restés explicables. Vous avez testé une autre paire de chemins réels, traité des erreurs ordinaires et conservé toutes les sources. Le défi vous demandera de combiner collecte par identité et vérification pour un autre équipement de voyage.