0Pricing
Learn Rust Coding · Lezione

Gestire lo stato dell'app

Conservi e aggiorni i dati dell'interfaccia.

Gestire lo stato dell'app è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 4 lezioni in totale.

Lo stato nella struct App

In egui, lo stato dell’applicazione è costituito da normali dati Rust che risiedono nella struct che implementa eframe::App. Non esiste un archivio speciale né un modello gestito dal framework.

I campi contengono tutto: valori dei moduli, selezioni, dati caricati e flag. A ogni frame, update legge e modifica direttamente questi campi tramite &mut self.

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

Derivare Default

eframe crea l’applicazione all’interno di una closure passata a run_native. Il modello più semplice consiste nell’usare #[derive(Default)] e creare l’istanza con App::default().

Per valori iniziali non predefiniti, implementi manualmente Default oppure aggiunga un costruttore che riceva il CreationContext per configurazioni come font o persistenza.

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

Un’unica fonte di verità

Poiché i widget prendono in prestito con &mut i campi a cui si appoggiano, la struct è sempre l’unica fonte di verità. Non esiste uno stato separato della vista da mantenere sincronizzato.

Una casella di controllo collegata a &mut self.enabled riflette e aggiorna direttamente quel valore booleano: se lo legge in un altro punto dello stesso frame, vede il valore aggiornato.

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

Rimandare le modifiche

Un problema sottile dei prestiti si presenta quando si itera su un Vec mentre si desidera rimuovere un elemento. Non è possibile modificare il vettore finché è attivo un prestito condiviso.

La soluzione consiste nel registrare l’azione desiderata in una variabile locale durante il ciclo e applicarla dopo la fine del ciclo.

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); }

Schermate guidate da enum

Per le applicazioni con più schermate, modelli la vista corrente come un campo di tipo enum. Il metodo update esegue il match su questo campo per decidere cosa disegnare.

In questo modo la navigazione è esplicita ed esaustiva: il compilatore obbliga a gestire ogni schermata, eliminando intere categorie di errori di instradamento.

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),
}

Memory di egui per lo stato della UI

Alcuni stati riguardano esclusivamente la UI, non il dominio dell’applicazione: sezioni compresse, posizioni di scorrimento e stato del trascinamento. egui li memorizza in ctx.memory, indicizzandoli tramite l’Id del widget.

Raramente dovrà accedervi direttamente, ma ctx.data_mut consente di memorizzare piccoli valori associati a un id, persistenti tra i frame, senza appesantire la struct dell’applicazione.

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));

Lavoro in background con i channel

Non blocchi mai update con operazioni I/O lente: il ciclo a 60 fps si bloccherebbe. Avvii un thread e comunichi tramite un channel std::sync::mpsc.

Il worker invia indietro i risultati; a ogni frame, update svuota il receiver senza bloccare usando try_recv. Chiami ctx.request_repaint() dal worker, così la UI si ridisegna quando arrivano nuovi dati.

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

Avviare il worker

Cloni Context e il sender all’interno del thread. La copia è economica: internamente è un Arc e consente al worker di richiedere il ridisegno.

Sposti la proprietà degli input del lavoro nella closure, così da soddisfare il borrow checker ed evitare problemi di durata dei prestiti.

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

Rendere persistente lo stato

eframe può serializzare l’applicazione tra un’esecuzione e l’altra. Abiliti la feature persistence, derivi serde::Serialize / Deserialize e implementi App::save.

All’avvio, legga lo stato salvato da cc.storage nel costruttore, ricorrendo ai valori predefiniti quando non è stato memorizzato nulla.

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; }
}

Mantenere leggero update

Poiché update viene eseguito a ogni frame, eviti di ricalcolare al suo interno dati derivati costosi. Memorizzi i risultati nei campi e li ricalcoli solo quando cambiano gli input.

Un modello comune consiste nel tenere traccia di un flag dirty impostato da Response::changed() e ricostruire le cache all’inizio di update solo quando il flag è attivo.

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

La proprietà mantiene il controllo

Il tema ricorrente è questo: egui si affida alla proprietà di Rust per gestire lo stato, invece di usare framework appositi. La struct possiede i dati, &mut self concede l’accesso esclusivo per ogni frame e i thread comunicano tramite channel.

Non ci sono sottoscrizioni nascoste né grafi di callback, quindi è possibile ragionare in modo locale ed esplicito su quando e come cambia lo stato.

Verifica rapida

Come dovrebbe eseguire un recupero lento dalla rete?

Riepilogo

Lo stato dell’applicazione è costituito da normali campi della struct eframe::App, modificati tramite &mut self a ogni frame; la struct diventa così l’unica fonte di verità.

Rimandi le modifiche durante l’iterazione, modelli le schermate con gli enum, deleghi il lavoro lento ai thread tramite channel e renda persistente lo stato usando l’archiviazione di eframe. Mantenga leggero update memorizzando nella cache i dati derivati e controllandoli con flag di modifica. Prossimo argomento: preparare l’applicazione per la distribuzione.

Domande Frequenti

La lezione «Gestire lo stato dell'app» è gratuita?

Sì — il testo completo di «Gestire lo stato dell'app» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 4 lezioni in totale.

Cosa imparerò in «Gestire lo stato dell'app»?

Conservi e aggiorni i dati dell'interfaccia. Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Learn Rust Coding?

Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Gestire lo stato dell'app»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?

Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Fondamenti dell'interfaccia UI immediate-mode
  2. Widget e layout
  3. Gestire lo stato dell'app
  4. Distribuire un'app desktop
← Torna a Learn Rust Coding