You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 10:04:57