命令系统 #

一、命令基础 #

1.1 什么是命令 #

命令是 Tauri 中前后端通信的核心机制。前端通过 invoke() 调用后端定义的 Rust 函数。

text
┌─────────────┐     invoke()     ┌─────────────┐
│   前端      │ ───────────────► │   后端      │
│ JavaScript  │                  │   Rust      │
│             │ ◄─────────────── │  Command    │
│             │     Result       │             │
└─────────────┘                  └─────────────┘

1.2 定义命令 #

rust
// 使用 #[tauri::command] 宏定义命令
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

// 注册命令
.invoke_handler(tauri::generate_handler![greet])

1.3 调用命令 #

typescript
import { invoke } from '@tauri-apps/api/core';

const result = await invoke<string>('greet', { name: 'World' });
console.log(result); // "Hello, World!"

二、参数传递 #

2.1 基本类型 #

rust
#[tauri::command]
fn basic_types(
    string_param: String,
    int_param: i32,
    float_param: f64,
    bool_param: bool,
) -> String {
    format!("string: {}, int: {}, float: {}, bool: {}",
        string_param, int_param, float_param, bool_param)
}
typescript
await invoke('basic_types', {
    stringParam: 'hello',
    intParam: 42,
    floatParam: 3.14,
    boolParam: true
});

2.2 可选参数 #

rust
#[tauri::command]
fn optional_param(name: Option<String>) -> String {
    match name {
        Some(n) => format!("Hello, {}!", n),
        None => "Hello, stranger!".to_string(),
    }
}
typescript
// 传递参数
await invoke('optional_param', { name: 'World' }); // "Hello, World!"

// 不传递参数
await invoke('optional_param', {}); // "Hello, stranger!"

2.3 结构体参数 #

rust
use serde::Deserialize;

#[derive(Deserialize)]
struct User {
    name: String,
    age: u32,
    email: String,
}

#[tauri::command]
fn create_user(user: User) -> String {
    format!("Created user: {} ({} years old)", user.name, user.age)
}
typescript
await invoke('create_user', {
    user: {
        name: 'Alice',
        age: 25,
        email: 'alice@example.com'
    }
});

2.4 集合类型 #

rust
#[tauri::command]
fn process_list(items: Vec<String>) -> usize {
    items.len()
}

#[tauri::command]
fn process_map(data: std::collections::HashMap<String, i32>) -> i32 {
    data.values().sum()
}
typescript
// 列表
await invoke('process_list', { items: ['a', 'b', 'c'] });

// Map
await invoke('process_map', { data: { a: 1, b: 2, c: 3 } });

三、返回值处理 #

3.1 基本返回类型 #

rust
#[tauri::command]
fn return_string() -> String {
    "Hello".to_string()
}

#[tauri::command]
fn return_number() -> i32 {
    42
}

#[tauri::command]
fn return_bool() -> bool {
    true
}

#[tauri::command]
fn return_option() -> Option<String> {
    Some("value".to_string())
}

3.2 结构体返回 #

rust
use serde::Serialize;

#[derive(Serialize)]
struct UserInfo {
    id: u32,
    name: String,
    active: bool,
}

#[tauri::command]
fn get_user() -> UserInfo {
    UserInfo {
        id: 1,
        name: "Alice".to_string(),
        active: true,
    }
}
typescript
interface UserInfo {
    id: number;
    name: string;
    active: boolean;
}

const user = await invoke<UserInfo>('get_user');
console.log(user.name); // "Alice"

3.3 集合返回 #

rust
#[tauri::command]
fn get_users() -> Vec<UserInfo> {
    vec![
        UserInfo { id: 1, name: "Alice".to_string(), active: true },
        UserInfo { id: 2, name: "Bob".to_string(), active: false },
    ]
}

#[tauri::command]
fn get_config() -> std::collections::HashMap<String, String> {
    let mut config = std::collections::HashMap::new();
    config.insert("theme".to_string(), "dark".to_string());
    config.insert("lang".to_string(), "en".to_string());
    config
}

四、错误处理 #

4.1 Result 类型 #

rust
#[tauri::command]
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}
typescript
try {
    const result = await invoke<number>('divide', { a: 10, b: 2 });
    console.log(result); // 5
} catch (error) {
    console.error(error); // "Division by zero"
}

4.2 自定义错误类型 #

rust
use serde::Serialize;

#[derive(Debug, Serialize)]
struct AppError {
    code: String,
    message: String,
}

impl From<std::io::Error> for AppError {
    fn from(error: std::io::Error) -> Self {
        AppError {
            code: "IO_ERROR".to_string(),
            message: error.to_string(),
        }
    }
}

#[tauri::command]
fn read_config() -> Result<String, AppError> {
    std::fs::read_to_string("config.json")?;
    Ok("success".to_string())
}

4.3 使用 anyhow #

rust
use anyhow::Result;

#[tauri::command]
fn complex_operation() -> Result<String> {
    // 使用 ? 操作符自动转换错误
    let content = std::fs::read_to_string("file.txt")?;
    Ok(content)
}

五、异步命令 #

5.1 异步函数 #

rust
#[tauri::command]
async fn async_greet(name: String) -> String {
    // 模拟异步操作
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    format!("Hello, {}!", name)
}

5.2 异步文件操作 #

rust
#[tauri::command]
async fn read_file_async(path: String) -> Result<String, String> {
    tokio::fs::read_to_string(&path)
        .await
        .map_err(|e| e.to_string())
}

5.3 异步 HTTP 请求 #

rust
#[tauri::command]
async fn fetch_data(url: String) -> Result<String, String> {
    let response = reqwest::get(&url)
        .await
        .map_err(|e| e.to_string())?;
    
    let body = response.text()
        .await
        .map_err(|e| e.to_string())?;
    
    Ok(body)
}

六、状态管理 #

6.1 共享状态 #

rust
use std::sync::Mutex;

struct AppState {
    counter: Mutex<i32>,
}

#[tauri::command]
fn increment(state: tauri::State<AppState>) -> i32 {
    let mut counter = state.counter.lock().unwrap();
    *counter += 1;
    *counter
}

#[tauri::command]
fn get_counter(state: tauri::State<AppState>) -> i32 {
    *state.counter.lock().unwrap()
}

// 注册状态
tauri::Builder::default()
    .manage(AppState {
        counter: Mutex::new(0),
    })
    .invoke_handler(tauri::generate_handler![increment, get_counter])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");

6.2 多状态管理 #

rust
struct Database {
    connection: Mutex<String>,
}

struct Cache {
    data: Mutex<std::collections::HashMap<String, String>>,
}

#[tauri::command]
fn use_multiple_states(
    db: tauri::State<Database>,
    cache: tauri::State<Cache>,
) -> String {
    // 使用多个状态
    "ok".to_string()
}

// 注册多个状态
tauri::Builder::default()
    .manage(Database { connection: Mutex::new("connection".to_string()) })
    .manage(Cache { data: Mutex::new(std::collections::HashMap::new()) })
    .invoke_handler(tauri::generate_handler![use_multiple_states])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");

七、窗口访问 #

7.1 获取窗口 #

rust
#[tauri::command]
async fn close_window(window: tauri::Window) {
    window.close().await.unwrap();
}

#[tauri::command]
async fn set_title(window: tauri::Window, title: String) {
    window.set_title(&title).await.unwrap();
}

7.2 获取应用句柄 #

rust
#[tauri::command]
fn get_app_info(app: tauri::AppHandle) -> String {
    format!("{} - {}",
        app.config().product_name.clone().unwrap_or_default(),
        app.config().version.clone().unwrap_or_default()
    )
}

八、命令注册 #

8.1 基本注册 #

rust
.invoke_handler(tauri::generate_handler![
    greet,
    increment,
    get_counter,
])

8.2 模块化注册 #

rust
mod commands {
    pub mod file {
        #[tauri::command]
        pub fn read() -> String { "read".to_string() }
        
        #[tauri::command]
        pub fn write() -> String { "write".to_string() }
    }
    
    pub mod system {
        #[tauri::command]
        pub fn info() -> String { "info".to_string() }
    }
}

.invoke_handler(tauri::generate_handler![
    commands::file::read,
    commands::file::write,
    commands::system::info,
])

九、TypeScript 类型 #

9.1 类型定义 #

typescript
// types/commands.ts
export interface User {
    id: number;
    name: string;
    email: string;
}

export interface AppError {
    code: string;
    message: string;
}

export interface Commands {
    greet: (name: string) => Promise<string>;
    getUser: () => Promise<User>;
    create_user: (user: User) => Promise<void>;
}

9.2 类型安全调用 #

typescript
// utils/tauri.ts
import { invoke } from '@tauri-apps/api/core';

export async function invokeTyped<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
    return invoke<T>(cmd, args);
}

// 使用
const user = await invokeTyped<User>('get_user');

十、最佳实践 #

10.1 命令命名 #

rust
// 推荐:动词开头,清晰描述功能
#[tauri::command]
fn get_user() -> User { /* ... */ }

#[tauri::command]
fn create_user() -> User { /* ... */ }

#[tauri::command]
fn delete_user() -> bool { /* ... */ }

// 不推荐:模糊命名
#[tauri::command]
fn user() -> User { /* ... */ }

10.2 参数验证 #

rust
#[tauri::command]
fn create_user(name: String, email: String) -> Result<User, String> {
    if name.is_empty() {
        return Err("Name cannot be empty".to_string());
    }
    
    if !email.contains('@') {
        return Err("Invalid email format".to_string());
    }
    
    Ok(User { name, email })
}

10.3 批量操作 #

rust
// 不推荐:多次调用
#[tauri::command]
fn get_user(id: u32) -> User { /* ... */ }

// 推荐:批量获取
#[tauri::command]
fn get_users(ids: Vec<u32>) -> Vec<User> { /* ... */ }

十一、调试技巧 #

11.1 日志输出 #

rust
#[tauri::command]
fn debug_command(param: String) -> String {
    println!("Received param: {}", param);
    format!("Processed: {}", param)
}

11.2 错误追踪 #

rust
#[tauri::command]
fn tracked_operation() -> Result<String, String> {
    std::fs::read_to_string("file.txt")
        .map_err(|e| {
            eprintln!("Error reading file: {}", e);
            format!("Failed to read file: {}", e)
        })
}

十二、总结 #

12.1 核心要点 #

要点 说明
命令定义 使用 #[tauri::command]
参数传递 支持基本类型、结构体、集合
返回值 支持同步和异步返回
错误处理 使用 Result 类型
状态管理 通过 tauri::State 共享

12.2 下一步 #

现在你已经掌握了 Tauri 的命令系统,接下来让我们学习 状态管理,了解如何在应用中管理共享状态!

最后更新:2026-03-28