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 限制。
性能
粗略排序(桌面场景):
- Slint(编译期布局 + 可选 Skia)整体帧率最稳,内存最低
- iced(wgpu 自绘)渲染效率高,但 VirtualDOM-less 的 diff 策略在大列表上需要手动优化
- 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 已经从"能用"走向"好用",值得持续关注。