Cél és előfeltétel

Egy munka lehet várakozó, folyamatban lévő vagy elkészült. Ha ezt három külön logikai mezőben tárolod, akár mindhárom egyszerre igaz lehet. Egy enum azt fejezi ki, hogy az érték a felsorolt változatok egyikéhez tartozik. Ebben a leckében egy egyszerű feladatállapotot építesz, és megvizsgálod, mely adatoknak van értelmük az egyes esetekben.

Előfeltétel a structok és metódusok, valamint a kölcsönzés. A külön futtatható edition 2024 programok szándékosan aprók. Minden új változatnál először fogalmazd meg a jelentést és a hozzá tartozó adatot, csak utána írd le a Rust típust. A névnek önmagában is segítenie kell az olvasást.

Egy érték, egy változat

Az enum lehetséges változatai a típus definíciójában szerepelnek. Egy konkrét érték egyszerre egy változatot képvisel. Így a várakozó és elkészült jelző nem lehet ugyanannak az értéknek két egymástól függetlenül átírható állapota. Ez szerkezeti garancia, nem pusztán megjegyzés a változók mellett. A típust használó függvénynek a lehetséges esetekkel kell számolnia.

Az enum változata adatot is hordozhat. Az elkészült munka kaphat eredményként saját szöveget, a várakozóhoz viszont nem kell üres eredményszöveget tárolni. Ettől még a String belül lehet üres; a típus itt azt rendezi, hogy az eredmény melyik állapothoz tartozik. Az eredmény tartalmi megfelelőségét további szabály ellenőrzi, ha a feladat igényli.

A match a teljes esetkört vizsgálja

A match egy érték változatához illő ágat választ. Ha minden változatot név szerint felsorolsz, a fordító segít észrevenni, amikor egy új eset megjelenése után egy régi feldolgozó hiányossá válik. Egy általános aláhúzás ág kényelmes lehet, de ezt a konkrét emlékeztetőt el is rejtheti. Kis, zárt állapotmodellnél ezért érdemes megfontolni az esetek teljes felsorolását.

Olvasáshoz az enumot is kölcsönözheted. A kölcsönzött match nem veszi ki a String eredményt a tulajdonosból, ezért a teljes állapot később is használható. A megjelenítő függvény saját új String értéket készíthet, amely független a bemenettől. A két külön döntésre figyelj: a bemenethez csak hozzáférünk, a megjelenítési eredményt viszont mi állítjuk elő.

Az állapotváltás külön szabály

Az enum önmagában nem dönti el, milyen sorrendben engeded az átmeneteket. A program akár egy várakozó értéket is azonnal készre cserélhetne, ha ilyen függvényt írnál. A feladatban az indítást korlátozzuk: indulni csak várakozásból lehet. Ezt a műveletek feltételei őrzik, és sikertelen kérésnél a korábbi érték megmarad.

A változatlan elutasítást ugyanazon az értéken érdemes ellenőrizni. Ha minden próbához új példányt készítesz, könnyebben elsikkad, hogy az első siker után már más állapotból indulsz. A tesztelt esetek: várakozásból indulás, az ismételt indítás elutasítása, és külön példányon a kész állapotból érkező indítási kérés elutasítása. Ez készít elő egy valódi kis nyilvántartást a következő leckében.

1. feladat: egyszerű állapotból címke

Definiálj három adat nélküli változatot, majd írj olvasó függvényt, amely mindegyikhez rövid szövegcímkét ad. A visszatérő szövegek rögzített literálok lehetnek. Mindhárom ágat ellenőrizd, mert egyetlen helyes címke nem bizonyítja a teljes döntést. A függvény ne módosítsa és ne fogyassza el az átadott állapotot.

Megoldás
enum Allapot { Varakozik, Fut, Kesz }
fn cimke(allapot: &Allapot) -> &'static str {
    match allapot {
        Allapot::Varakozik => "várakozik",
        Allapot::Fut => "fut",
        Allapot::Kesz => "kész",
    }
}
fn main() {
    assert_eq!(cimke(&Allapot::Varakozik), "várakozik");
    assert_eq!(cimke(&Allapot::Fut), "fut");
    assert_eq!(cimke(&Allapot::Kesz), "kész");
}

A visszaadott literálok a teljes programfutás alatt érvényes szövegek. Nem a függvényben készített ideiglenes String referenciáját adjuk vissza.

2. feladat: eredmény csak a kész állapotban

A következő modellnek két változata legyen: várakozás és elkészülés. Csak a kész változat hordozzon String eredményt. A leíró függvény fogadjon referenciát, és készítsen saját megjelenítési szöveget. Vizsgáld meg mindkét állapotot, majd a kész értéket írasd le másodszor is, ezzel jelezve, hogy az első hívás nem vitte el.

Megoldás
enum Munka { Varakozik, Kesz { eredmeny: String } }
fn leiras(munka: &Munka) -> String {
    match munka {
        Munka::Varakozik => String::from("még nincs eredmény"),
        Munka::Kesz { eredmeny } => format!("eredmény: {eredmeny}"),
    }
}
fn main() {
    let kesz = Munka::Kesz { eredmeny: String::from("42 sor") };
    assert_eq!(leiras(&Munka::Varakozik), "még nincs eredmény");
    assert_eq!(leiras(&kesz), "eredmény: 42 sor");
    assert_eq!(leiras(&kesz), "eredmény: 42 sor");
}

A várakozásnak nincs kötelező, értelmetlen üres eredménymezője. A különbséget a modell hordozza, nem a megjelenítő próbálja egy üres szövegből kitalálni.

3. feladat: indulás egyetlen megengedett állapotból

Írj indító metódust egy háromváltozatos állapoton. Várakozásból futásba váltson és igazat adjon. Futásból vagy kész állapotból utasítsa el a kérést változtatás nélkül. Ellenőrizd a sikeres hívást és közvetlenül utána a második próbát is. A kész állapot külön példánnyal is maradjon változatlan.

Megoldás
#[derive(Debug, PartialEq, Eq)]
enum Allapot { Varakozik, Fut, Kesz }
impl Allapot {
    fn indit(&mut self) -> bool {
        match self {
            Self::Varakozik => { *self = Self::Fut; true }
            Self::Fut | Self::Kesz => false,
        }
    }
}
fn main() {
    let mut allapot = Allapot::Varakozik;
    assert!(allapot.indit());
    assert_eq!(allapot, Allapot::Fut);
    assert!(!allapot.indit());
    assert_eq!(allapot, Allapot::Fut);
    let mut kesz = Allapot::Kesz;
    assert!(!kesz.indit());
    assert_eq!(kesz, Allapot::Kesz);
}

A csillagos értékadás a módosítható referencián keresztül cseréli az állapotot. Az elutasító ágban nincs értékadás, ezért az adat megőrzése a kódból és az állításokból is követhető.

Elfogadási feltételek

  • A címkéző minden változatot név szerint kezel, mindháromhoz a megfelelő szöveget adja.
  • A kész munka hordoz eredményt, és a kölcsönzött leírás után ismét használható.
  • Az indítás csak várakozásból sikeres; az ismételt és a kész állapotból induló kérés változatlanul elutasított.

Továbblépés

A struktúrák és az egymást kizáró állapotok most együtt is használhatók. A könyvtári katalógus miniprojektben könyveket keresel, kölcsönzést indítasz, és ellenőrzöd, hogy a hibás kérés nem írja át a korábbi adatot.