Cél és előfeltétel
Egy néhány soros programban minden függvény elfér egymás mellett. Ahogy megjelenik a bemenet ellenőrzése, a feldolgozás és a megjelenítés, egyre nehezebb eldönteni, mely részek tartoznak össze. A modulok névteret és láthatósági határt adnak. Ebben a leckében nem a fájlok számát növeled, hanem a használható felületet teszed tudatosabbá.
Előfeltétel a structok és metódusok, valamint a fájlok és útvonalak. A példák edition 2024 főprogramok. Minden modul a teljes program saját kapcsos zárójelei között szerepel, ezért nincs elhallgatott második fájl. Később ugyanez a logikai szerkezet külön fájlokra is osztható, de a mostani gyakorlat megértéséhez erre nincs szükség.
A modul névteret épít
A mod kulcsszóval létrehozott modul összetartozó elemeket fog össze. Egy benne lévő függvény útvonalát a modul neve és kettős kettőspont jelöli. Ez segít megkülönböztetni, hogy egy feldolgozás vagy formázás nevű művelet a program melyik részéhez tartozik. A névtér nem futás közbeni tároló: önmagában nem készít állapotot és nem indít külön folyamatot.
A use rövidebb néven tesz elérhetővé egy már megnevezett elemet az adott hatókörben. Nem másolja a függvényt és nem kerüli meg a láthatóságot. Ha valami nem hozzáférhető egy útvonalon, a rövidebb import sem teszi azzá. A crate az aktuális crate gyökerére utal, a super pedig a szülőmodulhoz vezet. A példában a rövid útvonalakat és a teljes kiindulást is tudatosan választjuk.
A nyilvános felületet kell megőrizned
A modul elemei alapértelmezésben nem nyilvánosak a külső hívó számára. A pub jelölés egy elemet elérhetővé tehet, de a hozzá vezető modulútvonal láthatóságának is megfelelőnek kell lennie. A közvetlen szülő a saját almoduljának nyilvános elemeit használhatja. A privát belső segédet viszont nem szeretnénk a főprogram kényelmi függvényévé tenni.
A kisebb publikus felület kevesebb megőrzendő ígéretet jelent. Ha a főprogram csak egy feldolgozó függvényt használ, belül később lecserélheted a segédfüggvény nevét vagy működési módját anélkül, hogy minden hívót átírnál. Ez nem mentség a viselkedés csendes megváltoztatására: a nyilvános művelet dokumentált eredménye és hibája továbbra is szerződés.
Privát mezők és létrehozás
Egy nyilvános struct mezői nem válnak automatikusan nyilvánossá. Ezt arra használhatod, hogy az értéket ellenőrzött függvény készítse el, a későbbi olvasás pedig metóduson át történjen. Így a hívó nem írhatja át közvetlenül az ellenőrzött küszöböt egy érvénytelen értékre. Ez már erősebb határ, mint egy tetszőlegesen kitölthető adatrekord.
A modell itt csak egyetlen szabályt véd: a küszöb legfeljebb száz lehet. Nem állítjuk, hogy ettől minden mérés hiteles vagy a teljes program hibátlan. A jól kiválasztott láthatóság viszont segít megőrizni ezt az egy konkrét feltételt. A tesztben ezért a határértéket és az első tiltott értéket külön vizsgáljuk, nem pusztán egy kényelmes középső példát.
1. feladat: egy publikus művelet, egy belső segéd
Hozz létre szamolas modult. A nyilvános ar függvény egy kis darabszámhoz kétszáz forintos egységárat használjon, amelyet privát segéd ad vissza. A főprogram csak az ar függvényt hívja. Ellenőrizd a nulla és három darabot. A feladatban legfeljebb tíz darabbal számolunk, így a szorzás biztosan belefér a típusba.
Megoldás
mod szamolas {
fn egysegar() -> u32 { 200 }
pub fn ar(darab: u32) -> u32 { darab * egysegar() }
}
fn main() {
assert_eq!(szamolas::ar(0), 0);
assert_eq!(szamolas::ar(3), 600);
}
A segédfüggvény valóban használatban van, de nem a főprogram felülete. A nulla darabos állítás a publikus eredményt ellenőrzi, nem a belső függvény külön tesztelését igényli.
2. feladat: ellenőrzött küszöbtípus
Készíts nyilvános Kuszob structot privát mezővel. A létrehozó függvény száz fölött None értéket adjon, egyébként hozza létre a típust. Az elfogad metódus akkor jelezzen igazat, ha a mérés legalább a tárolt küszöb. Ellenőrizd a küszöb alatti, pontosan vele egyenlő és a létrehozási határ fölötti példát.
Megoldás
mod szures {
pub struct Kuszob { ertek: u32 }
impl Kuszob {
pub fn uj(ertek: u32) -> Option<Self> {
if ertek > 100 { None } else { Some(Self { ertek }) }
}
pub fn elfogad(&self, meres: u32) -> bool { meres >= self.ertek }
}
}
fn main() {
let kuszob = szures::Kuszob::uj(20).expect("érvényes küszöb");
assert!(!kuszob.elfogad(19));
assert!(kuszob.elfogad(20));
assert!(szures::Kuszob::uj(100).is_some());
assert!(szures::Kuszob::uj(101).is_none());
}
Az expect itt a saját, rögzített érvényes tesztadat állítását fejezi ki. Valódi felhasználói bemenetnél nem erre bíznánk az érvénytelenség hétköznapi kezelését.
3. feladat: szülőnek látható belső lépés
Építs program modult egy belso almodullal. A belső nem_ures függvény csak a szülőmodul számára legyen hozzáférhető. A publikus darab függvény számolja meg a nem csupán szóközökből álló sorokat. A főprogram egy use segítségével hívja rövid néven a publikus műveletet. Üres bemenetet és szóközös sorokat is ellenőrizz.
Megoldás
mod program {
mod belso {
pub(super) fn nem_ures(sor: &str) -> bool { !sor.trim().is_empty() }
}
pub fn darab(szoveg: &str) -> usize {
let mut darab = 0;
for sor in szoveg.lines() {
if belso::nem_ures(sor) { darab += 1; }
}
darab
}
}
use crate::program::darab;
fn main() {
assert_eq!(darab("alma\n \nkorte\n"), 2);
assert_eq!(darab(""), 0);
assert_eq!(darab(" \n\t\n"), 0);
}
A nyilvános művelet feladata és a belső vizsgálat neve külön szerepet kap. A főprogramnak nem kell ismernie a segédmodul útvonalát a sorok megszámlálásához.
Elfogadási feltételek
- A főprogram az árkalkuláció nyilvános műveletét hívja, a segéd a modul belső részlete marad.
- A küszöb privát mezőjét csak az ellenőrzött létrehozás állítja be; száz elfogadott, százegy elutasított.
- A belső segéd pub(super) láthatóságú, a publikus számláló üres és szóközös bemenetre is helyes.
Továbblépés
A modulhatár már elrejti a megvalósítás részleteit. A hibák és kilépési kódok leckében a sikertelen eredmény is világos felületet kap: külön kezeled a feldolgozás hibáját, az emberi üzenetet és a folyamat állapotát.