Learn Rust Coding · Lekcja

Zarządzanie stanem aplikacji

Przechowa Pan/Pani i zaktualizuje dane interfejsu.

Lekcja 3 z 413 kroki

Zarządzanie stanem aplikacji to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Stan w strukturze App

W egui stan aplikacji to zwykłe dane w Rust, przechowywane w strukturze implementującej eframe::App. Nie ma osobnego magazynu ani modelu zarządzanego przez framework.

Pola przechowują wszystko: dane formularzy, wybory, wczytane dane i flagi. W każdej klatce update bezpośrednio odczytuje te pola i modyfikuje je przez &mut self.

struct App {
    query: String,
    results: Vec<Item>,
    selected: Option<usize>,
    loading: bool,
}

Wyprowadzanie Default

eframe tworzy aplikację w domknięciu przekazanym do run_native. Najprostszy wzorzec to #[derive(Default)] i utworzenie obiektu za pomocą App::default().

W przypadku wartości początkowych, których nie można wyznaczyć domyślnie, należy ręcznie zaimplementować Default albo dodać konstruktor przyjmujący CreationContext, aby skonfigurować na przykład czcionki lub trwałość danych.

impl App {
    fn new(cc: &eframe::CreationContext) -> Self {
        let mut app = Self::default();
        app.dark = cc.egui_ctx.style().visuals.dark_mode;
        app
    }
}

Jedno źródło prawdy

Ponieważ widgety pożyczają &mut do powiązanych z nimi pól, struktura zawsze jest jedynym źródłem prawdy. Nie ma osobnego stanu widoku, który trzeba synchronizować.

Pole wyboru powiązane z &mut self.enabled bezpośrednio odczytuje i aktualizuje tę wartość logiczną — odczytanie jej w dowolnym innym miejscu tej samej klatki zwróci aktualną wartość.

ui.checkbox(&mut self.enabled, "Enabled");
if self.enabled {
    ui.label("Feature is on");
}

Odroczone modyfikacje

Istnieje subtelny problem z pożyczaniem: często iteruje się po Vec, chcąc jednocześnie usunąć z niego element. Nie można modyfikować wektora, gdy aktywna jest pożyczka współdzielona.

Rozwiązaniem jest zapisanie zamierzonej operacji w zmiennej lokalnej podczas pętli, a następnie wykonanie jej po zakończeniu pętli.

let mut to_remove = None;
for (i, item) in self.items.iter().enumerate() {
    ui.horizontal(|ui| {
        ui.label(&item.name);
        if ui.button("x").clicked() { to_remove = Some(i); }
    });
}
if let Some(i) = to_remove { self.items.remove(i); }

Ekrany sterowane enumem

W aplikacjach wieloekranowych bieżący widok można reprezentować jako pole typu enum. Metoda update dopasowuje do jego wartości, aby zdecydować, co narysować.

Dzięki temu nawigacja jest jawna i wyczerpująca — kompilator wymusza obsługę każdego ekranu, eliminując całe klasy błędów routingu.

enum Screen { Home, Settings, About }

match self.screen {
    Screen::Home => self.draw_home(ui),
    Screen::Settings => self.draw_settings(ui),
    Screen::About => self.draw_about(ui),
}

Pamięć egui dla stanu interfejsu

Część stanu dotyczy wyłącznie interfejsu, a nie domeny aplikacji — na przykład zwinięte sekcje, pozycje przewijania i stan przeciągania. egui przechowuje go w ctx.memory, używając identyfikatora widgetu Id jako klucza.

Zwykle nie trzeba uzyskiwać do niego bezpośredniego dostępu, ale ctx.data_mut pozwala przechowywać niewielkie wartości przypisane do identyfikatora, zachowywane między klatkami bez zaśmiecania struktury aplikacji.

let id = egui::Id::new("my_toggle");
let mut open = ctx.data_mut(|d| d.get_temp::<bool>(id).unwrap_or(false));
ui.checkbox(&mut open, "Open");
ctx.data_mut(|d| d.insert_temp(id, open));

Praca w tle z kanałami

Nigdy nie blokuj update powolnymi operacjami wejścia-wyjścia — zamrozi to pętlę działającą z częstotliwością 60 klatek na sekundę. Uruchom wątek i komunikuj się za pomocą kanału std::sync::mpsc.

Wątek roboczy odsyła wyniki, a update w każdej klatce opróżnia odbiornik bez blokowania za pomocą try_recv. Wywołaj ctx.request_repaint() z wątku roboczego, aby interfejs został wybudzony po nadejściu danych.

if let Ok(msg) = self.rx.try_recv() {
    self.results = msg;
    self.loading = false;
}

Uruchamianie wątku roboczego

Skopiuj Context oraz nadajnik do wątku. Kopia jest tania — wewnętrznie używa Arc — i pozwala wątkowi żądać odświeżenia.

Przenieś własność danych wejściowych pracy do domknięcia, aby spełnić wymagania borrow checkera i uniknąć problemów z czasem życia.

let tx = self.tx.clone();
let ctx = ctx.clone();
std::thread::spawn(move || {
    let data = expensive_load();
    let _ = tx.send(data);
    ctx.request_repaint();
});

Trwałe przechowywanie stanu

eframe może serializować aplikację między kolejnymi uruchomieniami. Włącz funkcję persistence, wyprowadź implementacje serde::Serialize / Deserialize i zaimplementuj App::save.

Podczas uruchamiania odczytaj zapisany stan z cc.storage w konstruktorze, a gdy niczego nie zapisano, użyj wartości domyślnych.

fn save(&mut self, storage: &mut dyn eframe::Storage) {
    eframe::set_value(storage, eframe::APP_KEY, self);
}
// in new():
if let Some(s) = cc.storage {
    if let Some(app) = eframe::get_value(s, eframe::APP_KEY) { return app; }
}

Utrzymywanie lekkiej metody update

Ponieważ update uruchamia się w każdej klatce, nie należy wykonywać w nim ponownie kosztownych obliczeń danych pochodnych. Wyniki należy buforować w polach i przeliczać tylko wtedy, gdy zmienią się dane wejściowe.

Typowy wzorzec polega na śledzeniu flagi dirty ustawianej przez Response::changed() i odbudowywaniu buforów na początku update tylko wtedy, gdy flaga jest ustawiona.

if self.dirty {
    self.filtered = self.filter_items();
    self.dirty = false;
}
for item in &self.filtered { ui.label(&item.name); }

Własność zapewnia spójność

Powracający motyw jest następujący: egui opiera zarządzanie stanem na własności Rusta, a nie na frameworku. Struktura jest właścicielem danych, &mut self zapewnia wyłączny dostęp w każdej klatce, a wątki komunikują się za pośrednictwem kanałów.

Nie ma ukrytych subskrypcji ani grafów callbacków, dlatego rozumienie tego, kiedy i jak zmienia się stan, pozostaje lokalne i jawne.

Szybki test

Jak należy wykonać powolne pobieranie danych z sieci?

Podsumowanie

Stan aplikacji to zwykłe pola struktury eframe::App, modyfikowane w każdej klatce przez &mut self, dzięki czemu struktura jest jedynym źródłem prawdy.

Odłóż modyfikacje wykonywane podczas iteracji, modeluj ekrany za pomocą enumów, przenoś powolne operacje do wątków komunikujących się przez kanały i zapisuj stan w magazynie eframe. Utrzymuj update w lekkiej postaci, buforując dane pochodne za flagami zmiany. Następnie zajmiemy się pakowaniem aplikacji do dystrybucji.

Bezpłatny start

Ucz się Rust dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
39
Lekcje
144

Często zadawane pytania

Czy lekcja „Zarządzanie stanem aplikacji” jest bezpłatna?

Tak — pełny tekst „Zarządzanie stanem aplikacji” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Co nauczysz się w „Zarządzanie stanem aplikacji”?

Przechowa Pan/Pani i zaktualizuje dane interfejsu. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Zarządzanie stanem aplikacji”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy UI w trybie immediate mode
  2. Widgety i układ
  3. Zarządzanie stanem aplikacji
  4. Pakowanie aplikacji desktopowej
← Powrót do Learn Rust Coding