Todo framework de GUI desktop em Rust responde a uma pergunta fundamental de arquitetura antes de qualquer outra: a UI é reconstruída do zero a cada frame, ou ela persiste como uma estrutura de dados que muda incrementalmente? Essa única decisão - modo imediato versus modo retido - explica mais sobre como egui, iced e Tauri diferem do que qualquer comparação de recursos de seus widgets.
Esta página é a âncora conceitual para a seção GUI Desktop. A página de noções básicas percorre o código em cada framework; esta página explica por que esse código parece tão diferente dependendo do framework de origem, para que as páginas mais aprofundadas sobre egui, iced, Tauri e estado e arquitetura façam sentido como variações de um tema comum, em vez de três APIs não relacionadas.
Frameworks de GUI em Rust se dividem em um eixo de arquitetura - o modo imediato reconstrói a UI a cada frame a partir do estado atual, o modo retido mantém uma árvore de widgets persistente e a atualiza em resposta a eventos discretos.
Por Que Importa: Essa escolha determina como você pensa sobre o estado, quão testável é sua lógica de UI, como o framework se comporta sob carga e o quanto a UI parece "nativa" versus "ferramenta".
Conceitos Chave:modo imediato, modo retido, árvore de widgets, Modelo-Atualização-Visualização (arquitetura Elm), WebView, comparação (diffing).
Quando Usar: Modo imediato para ferramentas internas, overlays de depuração e editores; modo retido/estilo Elm para aplicativos nativos voltados ao consumidor; baseado em WebView (Tauri) quando uma equipe já possui habilidades de UI web ou deseja um binário pequeno com um ecossistema frontend rico.
Limitações / Trade-offs: O modo imediato troca alguma eficiência de CPU e polimento de acessibilidade por simplicidade; o modo retido troca alguma sobrecarga arquitetural por testabilidade e desempenho nativo; abordagens WebView trocam uma pilha Rust pura por ferramentas web e risco de interoperação JS.
Tópicos Relacionados: programação reativa de UI, a arquitetura Elm, janelas nativas (winit), limites de segurança de IPC.
GUI de Modo Imediato (IMGUI) significa que toda a árvore de widgets é reconstruída a cada frame, diretamente do estado atual da sua aplicação. Não há um grafo de objetos persistente de botões e rótulos na memória entre os frames; em vez disso, sua função update é executada 60 vezes por segundo (ou sempre que uma repintura é solicitada), e cada execução diz "desenhe um botão aqui, um slider ali" com base nos valores atuais. egui é a principal biblioteca de modo imediato em Rust, emparelhada com a integração de janelas eframe.
GUI de Modo Retido é o modelo mais tradicional familiar de toolkits desktop: o framework mantém uma árvore persistente de objetos de widgets, e seu código muta essa árvore (ou uma descrição dela) em resposta a eventos, deixando o framework descobrir o que realmente mudou e repintar apenas a diferença. iced implementa isso através da arquitetura Elm - um Model puro, uma função update que transforma mensagens em novo estado do modelo, e uma função view que transforma o modelo em uma descrição de widget, que iced então compara com a do frame anterior.
Um terceiro caminho contorna a distinção imediato/retido inteiramente. Tauri não implementa seu próprio modelo de renderização - ele embuti o WebView nativo do sistema operacional (WebView2 no Windows, WKWebView no macOS, WebKitGTK no Linux) e deixa HTML, CSS e JavaScript padrão lidarem com a renderização, enquanto Rust é o proprietário do backend: acesso ao sistema de arquivos, integração com o SO e qualquer coisa sensível à segurança, comunicada através de uma fronteira de IPC. Entender essas três formas - reconstruir-a-cada-frame, árvore-persistente-com-comparação, e delegar-para-o-motor-do-navegador - é o modelo mental mais útil para escolher entre as opções de GUI desktop em Rust.
No egui, um frame começa quando a camada de janelas (winit, encapsulada por eframe) entrega eventos de entrada e chama seu método App::update com uma referência mutável à sua struct de aplicação e o egui::Context atual. Dentro dessa chamada, você emite declarações de sensação imperativa como ui.button("Save"), e egui internamente rastreia quais IDs de widget foram tocados neste frame, calcula o layout e pinta. Como toda a árvore é reconstruída a cada frame, não há etapa de comparação para seu código raciocinar - o estado vive diretamente em sua struct, e a "UI" é apenas uma projeção dela calculada a cada vez.
O iced de modo retido inverte esse fluxo. Sua função view(&self) -> Element<Message> é pura: dado o modelo atual, ela retorna uma descrição de como a UI deve parecer, e o runtime do iced compara essa descrição com a anterior para calcular o conjunto mínimo de mudanças visuais. A interação do usuário não muta nada diretamente - ela produz um valor Message, que o iced roteia para sua função update(&mut self, message: Message), que é o único lugar onde o estado muda. Esse loop unidirecional (Modelo -> Visualização -> Mensagem -> Atualização -> Modelo) é deliberadamente reminiscente da arquitetura da linguagem Elm, e é por isso que o código do iced se lê mais como um redutor do que um script de UI imperativo.
// iced: view é puro (modelo -> descrição), update é o único ponto de mutaçãofn update(count: &mut i32, message: Message) { match message { Message::Increment => *count += 1, // o ÚNICO lugar onde o estado muda }}
As mecânicas do Tauri são diferentes em tipo, não apenas em grau. O WebView possui todo o loop de renderização usando o pipeline de layout e pintura do próprio motor do navegador, que Rust nunca toca diretamente. O papel do Rust é expor funções #[tauri::command] que o frontend JavaScript invoca através de um canal IPC serializado, e manter State<T> que sobrevive entre essas invocações. Isso significa que a pergunta imediato/retido é respondida inteiramente no lado JavaScript (comparação de DOM virtual do React, reatividade compilada do Svelte, ou manipulação simples do DOM) - a preocupação arquitetural do Rust no Tauri é a fronteira de segurança do IPC, não o loop de renderização.
As características de desempenho divergem acentuadamente em escala. O egui de modo imediato recomputa o layout para cada widget visível a cada frame por design, o que é barato para dashboards e inspetores com algumas centenas de widgets, mas pode se tornar um custo real com telas profundamente aninhadas de mil widgets - a correção é quase sempre fazer computação cara em uma thread de background e obter resultados via canal, não lutar contra o loop de frame em si. O iced de modo retido paga um custo de comparação em vez disso, que escala melhor com UIs grandes e majoritariamente estáticas (uma tela de configurações com widgets raramente alterados), mas adiciona sobrecarga arquitetural para visualizações genuinamente rápidas (uma forma de onda ao vivo) onde o modelo "apenas redesenhe tudo" do modo imediato é frequentemente mais simples e igualmente rápido na prática.
Acessibilidade é um eixo subestimado. Toolkits de modo retido e UIs baseadas em WebView geralmente têm um caminho muito mais fácil para suporte a leitores de tela, porque a plataforma subjacente (APIs de widgets nativos ou a árvore de acessibilidade do navegador) já entende a estrutura persistente da UI. Frameworks de modo imediato reconstroem tudo a cada frame, o que torna mais difícil expor uma árvore de acessibilidade estável para APIs do SO - um trade-off genuíno e honesto, não uma lacuna temporária.
A arquitetura de estado também se compõe de forma diferente à medida que um aplicativo cresce. No egui, o estado naturalmente se acumula em uma grande struct App, a menos que você a divida deliberadamente, pois não há fronteira imposta pelo framework entre "estado da UI" e "estado do domínio". No iced, a arquitetura Elm força essa fronteira desde o primeiro dia - seu Modelé seu estado, Messageé seu vocabulário de eventos - o que custa mais cerimônia inicial, mas compensa em testabilidade, já que update é uma função pura que você pode testar unitariamente com valores simples e sem nenhuma janela.
Abordagem
Força
Fraqueza
Melhor Ajuste
Modo imediato (egui)
Modelo mental simples, iteração rápida, fácil integração com thread de background
Recomputa a cada frame, acessibilidade mais fraca, dispersão de estado em escala
Ferramentas internas, overlays de depuração, inspetores de engine de jogos
Modo Retido/Elm (iced)
update puro testável, comparação mantém UIs grandes eficientes, fronteiras de estado impostas
Mais arquitetura inicial, menos flexível para visualizações em rápida mudança
Aplicativos nativos voltados ao consumidor, equipes que gostam de fluxo unidirecional estilo Redux
WebView (Tauri)
Ecossistema web completo para UI, binário pequeno vs. Electron, Rust detém APIs sensíveis à segurança
Modelo de renderização vive fora do Rust, fronteira IPC deve ser cuidadosamente validada
Equipes com fortes habilidades de frontend web querendo empacotamento nativo
"Modo imediato significa que a UI é redesenhada na GPU a cada frame, não importa o quê." - Não exatamente; egui ainda rastreia se a entrada ou o estado realmente mudaram e pode pular a repintura quando nada a solicita, "imediato" descreve a reexecução do código do widget, não necessariamente trabalho contínuo na GPU.
"Modo retido é sempre mais rápido." - É mais rápido para UIs majoritariamente estáticas, mas a própria etapa de comparação tem um custo, e para UIs que mudam a cada frame de qualquer maneira (dados ao vivo, animações), o caminho mais simples do modo imediato pode vencer.
"Tauri é apenas Electron com passos extras." - A arquitetura é significativamente diferente: Tauri usa o WebView já instalado do sistema operacional em vez de empacotar um runtime Chromium inteiro, que é a fonte de seus binários muito menores.
"Você tem que escolher um framework para o seu aplicativo inteiro." - Configurações híbridas são comuns, mais visivelmente bevy_egui, que sobrepõe uma UI de depuração de modo imediato sobre o próprio grafo de cena de modo retido de uma engine de jogos.
"A arquitetura Elm é exclusiva do iced." - É um padrão geral (fluxo de dados unidirecional, funções de atualização puras) que aparece bem além do Rust, iced simplesmente a implementa nativamente para GUIs desktop.
Qual é a diferença em uma frase entre modo imediato e modo retido?
O modo imediato reconstrói toda a descrição do widget a partir do estado a cada frame; o modo retido mantém uma árvore de widgets persistente e atualiza apenas o que mudou.
Por que egui se autodenomina "modo imediato" se ele ainda rastreia IDs de widgets entre os frames?
Ele rastreia IDs para coisas como foco e estado de animação, mas seu código de aplicação reemite toda a descrição da UI a cada frame em vez de mutar um grafo de objetos persistente.
A comparação do iced é semelhante ao DOM virtual do React?
Conceitualmente sim - ambos computam uma nova descrição de UI a partir do estado e a comparam com a anterior para minimizar o trabalho real de renderização.
Por que o binário do Tauri é menor que o do Electron?
Tauri embuti o WebView já instalado do sistema operacional em vez de empacotar um runtime Chromium inteiro dentro do aplicativo, que é de onde vem a maior parte do tamanho do Electron.
Posso testar a lógica da minha UI sem abrir uma janela?
No iced, sim - update é uma função pura de modelo e mensagem, então você pode chamá-la diretamente em um teste unitário. No egui, é mais difícil porque o código da UI é executado dentro do callback update(ctx, ...) vinculado ao loop de frame.
Por que engines de jogos favorecem UI de modo imediato para ferramentas de depuração?
Overlays de depuração mudam constantemente a cada frame de qualquer maneira, então o modelo "apenas redesenhe" do modo imediato corresponde à carga de trabalho, e bevy_egui se integra perfeitamente a um loop de renderização existente.
O modo imediato significa que não posso ter animações suaves?
Não - egui suporta animação e solicita repinturas ao animar, mas o estado da animação tem que viver em algum lugar explícito (geralmente na memória do Context) já que não há um objeto de widget persistente para mantê-lo implicitamente.
Uma arquitetura é mais "com cara de nativo" do que as outras?
Toolkits de modo retido com widgets específicos da plataforma tendem a ter a aparência mais nativa; egui renderiza deliberadamente sua própria aparência consistente entre plataformas em vez de usar widgets do SO; a aparência do Tauri depende inteiramente da UI web construída dentro dele.
Por que a acessibilidade difere tanto entre esses modelos?
Leitores de tela dependem de uma estrutura de UI persistente e consultável, que toolkits de modo retido e a árvore de acessibilidade do navegador já fornecem, enquanto frameworks de modo imediato precisam reconstruir e expor essa estrutura a cada frame.
O que acontece com a arquitetura de estado à medida que um aplicativo egui cresce?
O estado tende a se acumular em uma grande struct de aplicação, a menos que você a divida deliberadamente em módulos, já que egui não impõe uma fronteira de estado/UI da mesma forma que a arquitetura Elm faz.
A fronteira IPC do Tauri é uma preocupação de desempenho ou de segurança?
Principalmente segurança - cada comando é um limite de confiança entre o JavaScript frontend não confiável e o código Rust privilegiado, então a validação de entrada é mais importante aqui do que a taxa de transferência bruta de IPC para a maioria dos aplicativos.
Devo escolher o framework com base em 2D vs 3D, ou com base nesta questão de arquitetura?
Com base nesta questão primeiro - a tecnologia de renderização (wgpu, WebView) é frequentemente compartilhada ou substituível, mas a divisão imediato/retido/WebView determina como todo o seu codebase é estruturado e testado.