原生模块 #
一、原生模块概述 #
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