Rust 后端:状态管理
Rust 后端:状态管理
Section titled “Rust 后端:状态管理”在前面的章节中,我们创建了执行简单任务的 Rust 命令:接收输入、处理输入并返回结果。这些命令是无状态的——它们在每次执行之间不会记住任何信息。然而,大多数真实世界的应用程序都需要记住一些事情。无论是用户的登录会话、数据库连接还是简单的计数器,你都需要一种维护状态的方式。
无状态命令的挑战
Section titled “无状态命令的挑战”想象一下你的 Tauri 命令是餐厅里的一位服务员。在无状态模型中,每次服务员走到你的桌边时,他们都完全忘记了你是谁以及你之前点了什么。为了获得连贯的用餐体验,服务员需要一个记事本记录信息以便稍后查阅。在 Tauri 中,那个记事本就是 tauri::State。
Rust 函数天生是独立的。为了在主进程(应用程序启动的地方)和你的命令处理程序(前端请求时运行)之间共享数据,Tauri 提供了一个托管状态容器系统。
定义状态结构体
Section titled “定义状态结构体”首先,我们需要定义我们的状态是什么样子。在 Rust 中,我们使用 struct。在本教程中,我们将构建一个简单的计数器,即使前端重新加载也能保持其状态。
因为 Tauri 命令是异步的,并且可以同时从多个线程调用,我们不能简单地使用可变变量。我们需要将数据包装在线程安全的锁定机制中。最常见的标准方法是 Mutex (互斥锁)。
use std::sync::Mutex;
// 我们将整数封装在 Mutex 中,以允许安全的并发访问struct AppState { counter: Mutex<i32>,}初始化和管理状态
Section titled “初始化和管理状态”一旦结构体定义完毕,我们必须告诉 Tauri 来“管理”它。这发生在应用程序通过 Builder 进行设置期间。当你调用 .manage() 时,Tauri 会将此实例注入其内部状态注册表,使其可供任何命令访问。
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() { tauri::Builder::default() // 初始化状态,计数器从 0 开始 .manage(AppState { counter: Mutex::new(0) }) .invoke_handler(tauri::generate_handler![increment_counter]) .run(tauri::generate_context!()) .expect("error while running tauri application");}在命令中访问状态
Section titled “在命令中访问状态”现在 Tauri 正在管理我们的状态,我们如何取回它呢?我们在命令函数中使用 tauri::State 守卫作为参数。Tauri 的依赖注入系统会自动检测此参数并传入正确的状态实例。
要修改数据,我们必须首先 lock (锁定) Mutex。这确保了在任何给定时间只有一个命令可以修改计数器,从而防止竞态条件。
use tauri::State;
#[tauri::command]fn increment_counter(state: State<AppState>) -> i32 { // 锁定互斥锁以获得对内部整数的可变访问 // 这里使用 .unwrap() 来处理互斥锁“中毒”的罕见情况 let mut count = state.counter.lock().unwrap();
// 修改值 *count += 1;
// 将新值返回给前端 *count}整合所有部分
Section titled “整合所有部分”在前端,这看起来与任何其他命令调用完全相同。JavaScript 不需要了解 Mutex 或 State。它只是简单地要求后端递增并显示结果。
// Frontend JavaScript/TypeScriptimport { invoke } from '@tauri-apps/api/core';
async function addToCount() { const newCount = await invoke('increment_counter'); console.log("Current count from Rust:", newCount);}通过这种设置,你可以重新加载网页(Ctrl+R 或 Cmd+R),计数器也不会重置为零。状态存在于 Rust 后端进程中,该进程独立于 webview 而保持活跃。