原生模块 #

一、原生模块概述 #

1.1 为什么使用原生模块 #

原因 说明
性能 Rust 比 JavaScript 快
系统访问 直接访问系统 API
复用 复用现有 Rust 库
安全 Rust 内存安全

1.2 原生模块类型 #

text
┌─────────────────────────────────────────────────────────────┐
│                      原生模块类型                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  Rust 命令  │  │  FFI 调用   │  │  系统调用   │        │
│  │  Commands   │  │   FFI       │  │   Syscalls  │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                             │
│  简单易用          调用 C 库        底层系统访问             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、Rust 命令 #

2.1 基本命令 #

rust
#[tauri::command]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

2.2 异步命令 #

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)
}

2.3 复杂数据类型 #

rust
use serde::{Deserialize, Serialize};

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

#[tauri::command]
fn create_user(name: String, email: String) -> User {
    User {
        id: 1,
        name,
        email,
    }
}

#[tauri::command]
fn process_users(users: Vec<User>) -> usize {
    users.len()
}

2.4 错误处理 #

rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum AppError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("Network error: {0}")]
    Network(String),
}

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

三、FFI 调用 #

3.1 调用 C 库 #

rust
// 声明外部函数
extern "C" {
    fn strlen(s: *const i8) -> usize;
}

#[tauri::command]
fn string_length(s: String) -> usize {
    let c_string = std::ffi::CString::new(s).unwrap();
    unsafe { strlen(c_string.as_ptr()) }
}

3.2 使用系统库 #

rust
#[cfg(target_os = "windows")]
mod windows {
    #[tauri::command]
    pub fn get_system_info() -> String {
        // Windows 特定代码
        "Windows".to_string()
    }
}

#[cfg(target_os = "macos")]
mod macos {
    #[tauri::command]
    pub fn get_system_info() -> String {
        // macOS 特定代码
        "macOS".to_string()
    }
}

#[cfg(target_os = "linux")]
mod linux {
    #[tauri::command]
    pub fn get_system_info() -> String {
        // Linux 特定代码
        "Linux".to_string()
    }
}

#[tauri::command]
fn get_system_info() -> String {
    #[cfg(target_os = "windows")]
    { windows::get_system_info() }
    
    #[cfg(target_os = "macos")]
    { macos::get_system_info() }
    
    #[cfg(target_os = "linux")]
    { linux::get_system_info() }
}

3.3 使用 bindgen #

toml
# Cargo.toml
[build-dependencies]
bindgen = "0.69"
rust
// build.rs
use std::env;
use std::path::PathBuf;

fn main() {
    println!("cargo:rerun-if-changed=wrapper.h");
    
    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");
    
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

四、性能优化 #

4.1 避免不必要的序列化 #

rust
// ❌ 不好的做法:多次序列化
#[tauri::command]
fn get_large_data() -> String {
    let data = generate_large_data();
    serde_json::to_string(&data).unwrap()
}

// ✅ 好的做法:直接返回结构体
#[tauri::command]
fn get_large_data() -> LargeData {
    generate_large_data()
}

4.2 使用异步 I/O #

rust
use tokio::fs;

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

4.3 批量操作 #

rust
// ❌ 多次调用
#[tauri::command]
fn process_one(item: String) -> Result<String, String> {
    // 处理单个项目
    Ok(item.to_uppercase())
}

// ✅ 批量处理
#[tauri::command]
fn process_batch(items: Vec<String>) -> Result<Vec<String>, String> {
    Ok(items.into_iter().map(|s| s.to_uppercase()).collect())
}

4.4 使用缓存 #

rust
use std::collections::HashMap;
use std::sync::Mutex;

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

#[tauri::command]
fn get_cached_data(cache: tauri::State<Cache>, key: String) -> Option<String> {
    cache.data.lock().unwrap().get(&key).cloned()
}

#[tauri::command]
fn set_cached_data(cache: tauri::State<Cache>, key: String, value: String) {
    cache.data.lock().unwrap().insert(key, value);
}

五、线程安全 #

5.1 使用 Mutex #

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
}

5.2 使用 RwLock #

rust
use std::sync::RwLock;

struct AppState {
    data: RwLock<Vec<String>>,
}

#[tauri::command]
fn get_data(state: tauri::State<AppState>) -> Vec<String> {
    state.data.read().unwrap().clone()
}

#[tauri::command]
fn add_data(state: tauri::State<AppState>, item: String) {
    state.data.write().unwrap().push(item);
}

5.3 使用 Arc #

rust
use std::sync::{Arc, Mutex};

struct SharedData {
    items: Arc<Mutex<Vec<String>>>,
}

#[tauri::command]
fn process_shared(data: tauri::State<SharedData>) -> usize {
    data.items.lock().unwrap().len()
}

六、后台任务 #

6.1 异步任务 #

rust
use tokio::task;

#[tauri::command]
async fn start_background_task(app: tauri::AppHandle) -> Result<(), String> {
    let handle = app.clone();
    
    task::spawn(async move {
        loop {
            // 执行后台任务
            handle.emit("task-progress", "working").ok();
            tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        }
    });
    
    Ok(())
}

6.2 线程池 #

rust
use std::thread;

#[tauri::command]
fn parallel_process(items: Vec<String>) -> Vec<String> {
    items.into_iter()
        .map(|item| {
            thread::spawn(move || {
                // 处理项目
                item.to_uppercase()
            })
        })
        .collect::<Vec<_>>()
        .into_iter()
        .map(|h| h.join().unwrap())
        .collect()
}

七、内存管理 #

7.1 避免内存泄漏 #

rust
use std::sync::Arc;
use std::sync::weak::Weak;

struct ResourceManager {
    resources: Vec<Arc<Resource>>,
}

impl Drop for ResourceManager {
    fn drop(&mut self) {
        // 清理资源
        for resource in &self.resources {
            resource.cleanup();
        }
    }
}

7.2 使用 Box #

rust
#[tauri::command]
fn create_large_object() -> Box<LargeObject> {
    Box::new(LargeObject::new())
}

八、最佳实践 #

8.1 模块化组织 #

text
src-tauri/src/
├── commands/
│   ├── mod.rs
│   ├── file.rs
│   └── network.rs
├── models/
│   ├── mod.rs
│   └── user.rs
├── utils/
│   ├── mod.rs
│   └── error.rs
└── lib.rs

8.2 错误处理 #

rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum Error {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),
}

pub type Result<T> = std::result::Result<T, Error>;

8.3 日志记录 #

rust
use log::{info, error, debug};

#[tauri::command]
fn logged_operation() -> Result<(), String> {
    info!("Starting operation");
    
    match perform_operation() {
        Ok(_) => {
            info!("Operation completed");
            Ok(())
        }
        Err(e) => {
            error!("Operation failed: {}", e);
            Err(e.to_string())
        }
    }
}

九、总结 #

9.1 核心要点 #

要点 说明
Rust 命令 使用 #[tauri::command]
FFI 调用 调用 C 库和系统 API
性能优化 异步、批量、缓存
线程安全 Mutex、RwLock、Arc
内存管理 避免泄漏、正确释放

9.2 下一步 #

现在你已经掌握了原生模块,接下来让我们学习 性能优化,深入了解 Tauri 应用的性能优化技巧!

最后更新:2026-03-28