Cél és előfeltétel
Az előző leckében egyetlen rögzített rendelés árát számoltad ki. Most ugyanazt a szabályt több rendelésre szeretnéd alkalmazni másolás nélkül. A függvény nevet ad egy műveletnek, bemenetet fogad, és eredményt ad vissza. A cél nem minél több függvény létrehozása, hanem olyan határok kijelölése, amelyek mentén a programot könnyebb megérteni és ellenőrizni.
Előfeltétel az értékek és kifejezések ismerete. A megoldások önálló, edition 2024 főprogramok. Egyenként futtasd őket, és a kapott eredmény helyett először a függvény ígéretét fogalmazd meg. Milyen bemeneteket engedsz meg? Mit jelent a visszaadott szám? Milyen értékeknél lehet más az intuíciód, mint a leírt szabály?
Az aláírás az első magyarázat
Egy függvény paraméternevei csak a függvényen belül léteznek. Híváskor a hívó konkrét értékeket ad át nekik. A paraméterek típusát Rustban le kell írni; a visszatérési típust a nyíl után adod meg. Ez a rövid aláírás sok félreértést kizár: egy egész árat számoló függvényt nem tudsz véletlenül szöveggel meghívni, és a visszatérő értékről sem kell találgatnod.
Az azonos típus viszont nem bizonyít azonos jelentést. A darabszám és az egységár mindkettő lehet u32, ezért a fordító nem veszi észre, ha a sorrendjüket felcseréled. Válassz következetes sorrendet, beszédes neveket, és legalább egy aszimmetrikus példát: az öt és a kétszáz szerepe jobban látható, mint két egyforma számé. Később saját típusokkal is erősítheted a szerződést.
Az eredmény visszaadása és felhasználása
A függvény törzsének utolsó kifejezése lehet a visszatérő érték. A pontosvessző itt is számít, ahogyan egy egyszerű blokkban. A return kulcsszóval korábban is visszatérhetsz, de egy egyenes számításhoz általában nincs rá szükség. Kezdőként fontosabb a világos értékút, mint az összes lehetséges szintaktikai megoldás egyszerre történő kipróbálása.
Az eredmény kiírása és visszaadása külön feladat. Ha egy függvény csak kiírja az árat, a hívó nehezebben tud vele tovább számolni vagy közvetlenül összehasonlítani. A példáink számot adnak vissza; a képernyőre írást a főprogramra bízzuk. Ettől a számítás terminál nélkül is vizsgálható, és nem függ a megjelenített szöveg formátumától.
Kis műveletek összekapcsolása
Egy függvény hívhat másik függvényt. Ezt akkor érdemes használni, ha a kisebb művelet önmagában is értelmes nevet és szabályt kap. A percekből másodpercet készítő átváltás például külön ellenőrizhető, és egy összetettebb időszámítás része lehet. Az egységek nevének feltüntetése különösen hasznos, mert a fordító az azonos számtípus mögött nem látja a perc és a másodperc különbségét.
A függvény kiszervezése nem teszi automatikusan biztonságossá a számolást. Ezekben a gyakorlatokban a megadott kicsi értékekre vállalunk eredményt. A teljes u32 tartományt kezelő általános könyvtárnak túlcsordulási szabályt is kellene választania. A leírt korlát nem kibúvó: pontosan megmutatja, mire terjed ki az állításokkal ellenőrzött viselkedés.
1. feladat: újra felhasználható rendelési ár
Írj függvényt, amely az egységár, darabszám és egyszer felszámított csomagolás alapján adja meg a végösszeget. A paraméterek ebben a sorrendben következzenek. Ellenőrizd ugyanazzal a függvénnyel a háromdarabos rendelést és a nulla darabos határesetet. A függvényben ne legyen képernyőre írás, csak visszaadott eredmény.
Megoldás
fn vegosszeg(egysegar: u32, darab: u32, csomagolas: u32) -> u32 {
egysegar * darab + csomagolas
}
fn main() {
assert_eq!(vegosszeg(250, 3, 100), 850);
assert_eq!(vegosszeg(250, 0, 100), 100);
assert_eq!(vegosszeg(0, 3, 0), 0);
}
A nulla egységár külön ellenőrzés, nem a nulla darabszám ismétlése. Így két külön bemeneti szerepre is látható példát adunk, ugyanazzal a kis számítási szabállyal.
2. feladat: percekből másodperc
Készíts átváltó függvényt, majd hívd meg egy második függvényből, amely ehhez további másodperceket ad. A feladat bemenete legfeljebb száz perc és ötvenkilenc másodperc. Vizsgáld meg a csupa nulla és a két perc tizenöt másodperc esetét is. A paraméternevek őrizzék meg a mértékegységet.
Megoldás
fn masodpercre(perc: u32) -> u32 {
perc * 60
}
fn teljes_ido(perc: u32, tovabbi_masodperc: u32) -> u32 {
masodpercre(perc) + tovabbi_masodperc
}
fn main() {
assert_eq!(masodpercre(1), 60);
assert_eq!(teljes_ido(2, 15), 135);
assert_eq!(teljes_ido(0, 0), 0);
}
A belső függvény eredménye ugyanúgy egy érték, mint egy közvetlenül leírt szám. A külső függvény ebből folytatja a számolást, nem a terminálból olvassa vissza.
3. feladat: egész hányados és maradék
Egy iskolai feladathoz ötös csomagokba rendezel matricákat. Írj két függvényt: az egyik a teljes csomagok számát, a másik a maradék darabokat adja vissza. Próbáld ki a tizenhárom, tíz és nulla darabos esetet. A pozitív, rögzített osztó miatt itt a nullával osztás nem merül fel.
Megoldás
fn csomagok(darab: u32) -> u32 {
darab / 5
}
fn maradek(darab: u32) -> u32 {
darab % 5
}
fn main() {
assert_eq!((csomagok(13), maradek(13)), (2, 3));
assert_eq!((csomagok(10), maradek(10)), (2, 0));
assert_eq!((csomagok(0), maradek(0)), (0, 0));
}
A zárójeles pár itt két eredmény együttes ellenőrzésére szolgál. A maradékból nem lesz további teljes csomag; az osztás és a maradékképzés két összetartozó, de külön jelentésű művelet.
Elfogadási feltételek
- A rendelési függvény a megadott sorrendű paraméterekkel 850, 100 és 0 eredményt ad.
- Az időszámítás az átváltó függvényt használja; két perc tizenöt másodpercből 135 másodperc lesz.
- A matricák három esetében a teljes csomagok és a maradék értéke is ellenőrzött, képernyőkimenet vizsgálata nélkül.
Továbblépés
A bemenet és kimenet már külön látszik, de minden függvényünk ugyanazt a számítási utat járta be. A döntések és logikai feltételek leckében a bemenet alapján több szabály közül választasz, és a határértékeket is tudatosan megvizsgálod.