Rust GUI对比:iced vs Slint vs Dioxus

Rust 生态的 GUI 框架正在快速成熟。iced、Slint、Dioxus 是当前最活跃的三个方向,分别代表了 Elm 架构、声明式 DSL、React-like 三种设计思路。本文从 API 风格、渲染方式、性能和生态角度做一次横向对比。

设计理念速览

框架 灵感来源 核心思路 渲染后端
iced Elm 消息驱动、纯函数 view() wgpu / tiny-skia
Slint Qt/QML .slint DSL 描述 UI,编译期优化 Software / GL / Skia
Dioxus React RSX 宏、VirtualDOM diff WebView / WGPU / Terminal

iced 偏向 Elm 的单向数据流,所有状态变更走 Message -> update() -> view() 循环,调试友好但嵌套组件通信稍显冗长。

Slint 走自有 DSL 路线,UI 描述和逻辑分离,编译器可以在编译期做布局优化,带来更低的运行时开销。缺点是引入了一门新语言。

Dioxus 对 React 开发者几乎零学习成本:rsx! 宏、Hooks、Context,甚至有 SSR 支持。

API 风格对比

iced — Elm 架构

use iced::{widget::{button, column, text}, Element, Sandbox, Settings};

struct Counter { value: i64 }

#[derive(Debug, Clone)]
enum Message { Increment, Decrement }

impl Sandbox for Counter {
    type Message = Message;

    fn new() -> Self { Counter { value: 0 } }
    fn title(&self) -> String { "Counter".into() }

    fn update(&mut self, msg: Message) {
        match msg {
            Message::Increment => self.value += 1,
            Message::Decrement => self.value -= 1,
        }
    }

    fn view(&self) -> Element<Message> {
        column![
            button("+").on_press(Message::Increment),
            text(self.value),
            button("-").on_press(Message::Decrement),
        ].into()
    }
}

fn main() -> iced::Result {
    Counter::run(Settings::default())
}

Slint — 声明式 DSL

// counter.slint
export component Counter inherits Window {
    in-out property <int> value: 0;
    VerticalLayout {
        Button { text: "+"; clicked => { value += 1; } }
        Text { text: value; }
        Button { text: "-"; clicked => { value -= 1; } }
    }
}

Rust 侧只需加载并 run:

slint::include_modules!();

fn main() {
    let ui = Counter::new().unwrap();
    ui.run().unwrap();
}

Dioxus — React-like RSX

use dioxus::prelude::*;

fn app() -> Element {
    let mut count = use_signal(|| 0i64);
    rsx! {
        button { onclick: move |_| count += 1, "+" }
        p { "{count}" }
        button { onclick: move |_| count -= 1, "-" }
    }
}

fn main() {
    dioxus::launch(app);
}

渲染方式

iced 默认使用 wgpu 后端做 GPU 渲染,也可以回退到 tiny-skia 纯 CPU 渲染。自绘一切 widget,不依赖系统原生控件,视觉一致性好但和 OS 风格差异明显。

Slint 提供三种后端:纯软件渲染(适合嵌入式 MCU,无需 GPU)、OpenGL、Skia。在资源受限的嵌入式平台(如 STM32、ESP32)上,Slint 是目前唯一真正能跑的 Rust GUI 方案。

Dioxus 桌面端默认通过系统 WebView 渲染(类 Tauri),也支持 WGPU 自绘模式。WebView 模式下包体小、启动快,但性能上限受 WebView 限制。

性能

粗略排序(桌面场景):

  1. Slint(编译期布局 + 可选 Skia)整体帧率最稳,内存最低
  2. iced(wgpu 自绘)渲染效率高,但 VirtualDOM-less 的 diff 策略在大列表上需要手动优化
  3. Dioxus WebView 模式 受限于 WebView,复杂场景可能掉帧;WGPU 模式尚在早期

对于嵌入式/资源受限场景,Slint 的软件渲染器是独一档的选择。

生态成熟度

维度 iced Slint Dioxus
组件库 社区 widget 较多 内置组件丰富 依赖 HTML/CSS
文档质量 中等,示例多 好,有 IDE 插件 好,API 文档齐全
多平台 桌面 + Web(实验) 桌面 + 嵌入式 + Web 桌面 + Web + 移动端 + TUI
生产案例 少量 Slint 公司商业支持 早期采用者
许可证 MIT GPLv3 / 商业双授权 MIT + Apache 2.0

注意 Slint 的双授权模式——开源项目用 GPLv3 免费,闭源商业项目需要购买授权。

选型建议

  • 追求跨平台覆盖(桌面+Web+移动) -> Dioxus,生态最广
  • 嵌入式 / 资源受限 -> Slint,软件渲染 + 编译期优化
  • 喜欢 Elm 架构、纯 Rust 自绘 -> iced,社区活跃
  • 团队有 React 经验 -> Dioxus 上手最快
  • 需要商业支持 -> Slint 有公司背书

三个框架都还在快速迭代,2025 年的 Rust GUI 已经从"能用"走向"好用",值得持续关注。