如何在Tauri的Vue前端调用带状态的Rust结构体实例方法?
在Tauri中无需额外状态管理包调用带状态结构体实例方法的方案
问题背景
开发基于Rust后端+Vue前端的Tauri应用时,#[tauri::command]宏仅适用于纯函数,无法直接装饰需要保留实例状态的结构体方法(如RandomNumberGenerator的generate和used_numbers方法),导致前端无法调用这些带状态的实例方法。
解决方案:使用Tauri内置全局State管理
无需额外状态管理包,通过Tauri的State机制将结构体实例注册为全局线程安全状态,再编写顶层命令函数代理调用实例方法。
步骤1:改造结构体定义
移除结构体方法上的#[tauri::command]宏,保留原有业务逻辑:
// random_number_generator.rs use rand::Rng; pub struct RandomNumberGenerator { used_numbers_repository: Vec<i64>, } impl RandomNumberGenerator { pub fn new() -> Self { RandomNumberGenerator { used_numbers_repository: Vec::new() } } pub fn generate(&mut self, minimum: i64, maximum: i64) -> String { if minimum < 0 { return format!("Random number between {} and {}: minimum must be positive.", minimum, maximum); } if minimum >= maximum { return format!("Random number between {} and {}: maximum must be more than minimum.", minimum, maximum); } let mut rng = rand::thread_rng(); let mut number: i64 = rng.gen_range(minimum..maximum + 1); while self.used_numbers_repository.contains(&number) { number = rng.gen_range(minimum..maximum + 1); } self.used_numbers_repository.push(number); format!("A random number between {} and {}? Here you go: {}.", minimum, maximum, number) } pub fn used_numbers(&self) -> String { self.used_numbers_repository.iter().map(|&id| id.to_string() + " ").collect() } }
步骤2:注册全局状态并编写代理命令
在main.rs中,将结构体实例包装为Arc<Mutex>(保证多线程安全),注册为Tauri全局状态,再编写顶层命令函数代理调用实例方法:
// main.rs use std::sync::{Arc, Mutex}; mod random_number_generator; use random_number_generator::RandomNumberGenerator; use tauri::State; #[tauri::command] fn generate(state: State<'_, Arc<Mutex<RandomNumberGenerator>>>, minimum: i64, maximum: i64) -> String { let mut generator = state.lock().unwrap(); generator.generate(minimum, maximum) } #[tauri::command] fn used_numbers(state: State<'_, Arc<Mutex<RandomNumberGenerator>>>) -> String { let generator = state.lock().unwrap(); generator.used_numbers() } fn main() { let number_generator = Arc::new(Mutex::new(RandomNumberGenerator::new())); tauri::Builder::default() .manage(number_generator) .invoke_handler(tauri::generate_handler![generate, used_numbers]) .run(tauri::generate_context!()) .expect("error while running tauri application"); }
步骤3:前端调用保持不变
Vue组件无需修改,直接通过invoke调用对应的命令名即可(可新增查看已用数字的逻辑):
<!-- RandomGenerator.vue --> <script setup lang="ts"> import { ref } from "vue"; import { invoke } from "@tauri-apps/api/tauri"; const generatedMessage = ref(""); const usedNumbers = ref(""); const minimum = ref(0); const maximum = ref(999); async function generate() { generatedMessage.value = await invoke("generate", { minimum: minimum.value, maximum: maximum.value }) } async function getUsedNumbers() { usedNumbers.value = await invoke("used_numbers") } </script> <template> <div class="card"> <input type="number" v-model="minimum" placeholder="minimum" /> <input type="number" v-model="maximum" placeholder="maximum" /> <button type="button" @click="generate()">Generate</button> <button type="button" @click="getUsedNumbers()">View Used Numbers</button> </div> <p>{{ generatedMessage }}</p> <p>Used numbers: {{ usedNumbers }}</p> </template>
关键说明
Arc<Mutex>用于保证结构体实例在多线程环境下的安全访问,符合Tauri对State的Send + Sync要求- 顶层命令函数作为桥梁,通过
State获取结构体实例后调用其方法 - 前端调用逻辑完全无需修改,保持原有交互方式
内容的提问来源于stack exchange,提问作者VassilisM
相关产品推荐
相关产品推荐

