- 重构项目架构,采用四层架构模式 (Command → Service → Platform → Utils) - 实现命令面板功能,支持快捷搜索和特征分类 - 添加颜色取色功能,支持屏幕像素颜色获取 - 添加JSON格式化功能,支持JSON格式化和压缩 - 添加系统信息功能,显示操作系统和硬件信息 - 移除旧的状态文档和无用配置文件
27 KiB
27 KiB
Tauri 应用开发指南
目录
架构概述
四层架构
┌─────────────────────────────────────────────────┐
│ Command 层 │
│ 职责:参数验证、调用 Service、结果转换 │
│ 文件:src/commands/*.rs │
├─────────────────────────────────────────────────┤
│ Service 层 │
│ 职责:业务逻辑、流程编排、状态管理 │
│ 文件:src/services/*.rs │
├─────────────────────────────────────────────────┤
│ Platform 层 │
│ 职责:平台差异抽象、统一接口 │
│ 文件:src/platforms/*.rs │
├─────────────────────────────────────────────────┤
│ Utils 层 │
│ 职责:纯算法、无状态工具函数 │
│ 文件:src/utils/*.rs │
└─────────────────────────────────────────────────┘
依赖原则
- 单向依赖:上层依赖下层,下层不依赖上层
- 依赖链:Command → Service → Platform → Utils
- Utils 完全独立:只依赖标准库和 models
- Platform 通过 trait 解耦:Service 层通过 trait 调用,不关心具体实现
添加新功能的完整流程
步骤 1:需求分析
在开始编码前,明确以下内容:
- 功能描述:这个功能做什么?
- 用户交互:用户如何触发这个功能?
- 输入输出:需要什么参数?返回什么结果?
- 平台差异:不同平台是否需要不同实现?
- 错误场景:哪些情况下会出错?如何处理?
步骤 2:设计数据模型(如需要)
如果新功能需要新的数据结构,在 models/ 中定义:
// src/models/new_feature.rs
use serde::{Deserialize, Serialize};
/// 新功能的配置信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewFeatureConfig {
/// 配置项 1
pub option1: String,
/// 配置项 2
pub option2: u32,
}
/// 新功能的输出结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewFeatureResult {
/// 状态码
pub status: u16,
/// 结果数据
pub data: String,
}
规范:
- ✅ 使用中文注释
- ✅ 每个字段都要有注释说明含义
- ✅ 实现
Debug,Clone,Serialize,Deserialize - ✅ 结构体命名使用大驼峰(PascalCase)
- ✅ 字段命名使用下划线命名(snake_case)
步骤 3:实现工具函数(如果需要纯算法)
如果有纯算法逻辑,在 utils/ 中实现:
// src/utils/new_algorithm.rs
/// 新算法函数
///
/// 对输入数据进行处理
///
/// # 参数
///
/// * `input` - 输入数据
///
/// # 返回
///
/// 返回处理后的结果
///
/// # 示例
///
/// ```
/// use crate::utils::new_algorithm::process_data;
///
/// let result = process_data(42);
/// assert_eq!(result, 84);
/// ```
pub fn process_data(input: u32) -> u32 {
input * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_process_data() {
assert_eq!(process_data(2), 4);
assert_eq!(process_data(0), 0);
}
}
规范:
- ✅ 纯函数,无副作用
- ✅ 添加详细的文档注释
- ✅ 包含单元测试
- ✅ 不依赖任何外部状态
步骤 4:定义平台抽象(如果需要平台特定实现)
如果功能需要访问平台 API,定义 trait:
// src/platforms/new_feature.rs
use crate::error::AppResult;
/// 新功能平台抽象 trait
pub trait NewFeatureAccessor {
/// 执行平台特定的操作
///
/// # 参数
///
/// * `param1` - 参数 1 说明
///
/// # 返回
///
/// 返回操作结果
///
/// # 错误
///
/// 操作失败时返回错误
fn execute_platform_operation(&self, param1: &str) -> AppResult<String>;
}
/// 平台特定实现类型别名
#[cfg(windows)]
pub type PlatformNewFeature = crate::platforms::windows::new_feature_impl::WindowsNewFeature;
#[cfg(not(windows))]
pub type PlatformNewFeature = crate::platforms::windows::new_feature_impl::DummyNewFeature;
规范:
- ✅ 使用 trait 定义接口
- ✅ 所有方法返回
AppResult<T> - ✅ 方法参数使用引用(
&str而不是String) - ✅ 添加详细的文档注释
步骤 5:实现平台特定代码
// src/platforms/windows/new_feature_impl.rs
use crate::error::{AppError, AppResult};
use crate::platforms::new_feature::NewFeatureAccessor;
/// Windows 平台实现
#[cfg(windows)]
pub struct WindowsNewFeature;
#[cfg(windows)]
impl NewFeatureAccessor for WindowsNewFeature {
fn execute_platform_operation(&self, param1: &str) -> AppResult<String> {
// Windows 特定实现
Ok(format!("Windows: {}", param1))
}
}
/// 其他平台占位实现
#[cfg(not(windows))]
pub struct DummyNewFeature;
#[cfg(not(windows))]
impl NewFeatureAccessor for DummyNewFeature {
fn execute_platform_operation(&self, _param1: &str) -> AppResult<String> {
Err(AppError::PlatformNotSupported(
"此平台暂不支持该功能".to_string()
))
}
}
规范:
- ✅ 使用
#[cfg(windows)]条件编译 - ✅ 提供其他平台的占位实现
- ✅ 占位实现返回
PlatformNotSupported错误 - ✅ 使用中文错误消息
步骤 6:实现业务逻辑(Service 层)
// src/services/new_feature_service.rs
//! 新功能服务
//!
//! 提供新功能的核心业务逻辑
use crate::error::AppResult;
use crate::models::new_feature::{NewFeatureConfig, NewFeatureResult};
/// 新功能服务
pub struct NewFeatureService;
impl NewFeatureService {
/// 执行新功能
///
/// 根据配置执行相应的操作
///
/// # 参数
///
/// * `config` - 功能配置
///
/// # 返回
///
/// 返回执行结果
///
/// # 错误
///
/// - 配置无效时返回 `AppError::InvalidColorData`
/// - 平台不支持时返回 `AppError::PlatformNotSupported`
pub fn execute(&self, config: &NewFeatureConfig) -> AppResult<NewFeatureResult> {
// 1. 参数验证
if config.option1.is_empty() {
return Err(AppError::InvalidColorData(
"配置项 option1 不能为空".to_string()
));
}
// 2. 业务逻辑
let result = format!("处理: {} - {}", config.option1, config.option2);
// 3. 返回结果
Ok(NewFeatureResult {
status: 200,
data: result,
})
}
/// 执行新功能(异步版本)
///
/// 异步执行新功能
pub async fn execute_async(&self, config: NewFeatureConfig) -> AppResult<NewFeatureResult> {
// 使用 tokio 或其他异步运行时
Ok(self.execute(&config)?)
}
}
规范:
- ✅ 使用 struct 命名空间(如
NewFeatureService) - ✅ 所有方法返回
AppResult<T> - ✅ 参数验证放在 Service 层
- ✅ 添加详细的文档注释
- ✅ 包含同步和异步两个版本(如需要)
步骤 7:创建 Tauri 命令(Command 层)
// src/commands/new_feature_commands.rs
//! 新功能命令
//!
//! 定义新功能相关的 Tauri 命令
use crate::models::new_feature::{NewFeatureConfig, NewFeatureResult};
use crate::services::new_feature_service::NewFeatureService;
/// 执行新功能命令
///
/// Tauri 命令,用于从前端调用新功能
///
/// # 参数
///
/// * `config` - 功能配置
///
/// # 返回
///
/// 返回执行结果,包含状态码和数据
///
/// # 前端调用示例
///
/// ```typescript
/// import { invoke } from '@tauri-apps/api/tauri';
///
/// const result = await invoke('execute_new_feature', {
/// config: {
/// option1: 'test',
/// option2: 100
/// }
/// });
/// console.log(result.status); // 200
/// console.log(result.data); // "处理: test - 100"
/// ```
#[tauri::command]
pub fn execute_new_feature(config: NewFeatureConfig) -> Result<NewFeatureResult, String> {
// 创建服务实例
let service = NewFeatureService;
// 调用服务层
service
.execute(&config)
.map_err(|e| e.to_string())
}
/// 异步执行新功能命令
///
/// 异步版本的执行命令
///
/// # 参数
///
/// * `config` - 功能配置
///
/// # 返回
///
/// 返回执行结果
#[tauri::command]
pub async fn execute_new_feature_async(config: NewFeatureConfig) -> Result<NewFeatureResult, String> {
let service = NewFeatureService;
service
.execute_async(config)
.await
.map_err(|e| e.to_string())
}
规范:
- ✅ 使用
#[tauri::command]宏 - ✅ 返回类型为
Result<T, String> - ✅ 使用
.map_err(|e| e.to_string())转换错误 - ✅ 包含前端调用示例
- ✅ 参数使用结构体,便于扩展
- ✅ 添加详细的文档注释
步骤 8:注册模块
更新各模块的 mod.rs 和 lib.rs:
// src/models/mod.rs
pub mod color;
pub mod new_feature; // 新增
pub use color::{ColorInfo, RgbInfo, HslInfo};
pub use new_feature::{NewFeatureConfig, NewFeatureResult}; // 新增
// src/commands/mod.rs
pub mod color_commands;
pub mod window_commands;
pub mod new_feature_commands; // 新增
// src/lib.rs
.invoke_handler(tauri::generate_handler![
// ... 其他命令
commands::new_feature_commands::execute_new_feature,
commands::new_feature_commands::execute_new_feature_async,
])
规范:
- ✅ 按字母顺序排列
- ✅ 导出常用类型
- ✅ 注册所有新命令
步骤 9:错误处理扩展(如需要)
如果需要新的错误类型,在 error.rs 中添加:
// src/error.rs
#[derive(Debug)]
pub enum AppError {
// ... 现有错误类型
/// 新功能相关错误
NewFeatureFailed(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
// ... 现有错误
AppError::NewFeatureFailed(msg) => write!(f, "新功能执行失败: {}", msg),
}
}
}
规范:
- ✅ 错误类型使用中文描述
- ✅ 携带详细的错误信息(
String) - ✅ 在
Display实现中添加上下文
步骤 10:更新前端类型定义
在 src/types/ 或相关位置添加 TypeScript 类型定义:
// src/types/new-feature.ts
/**
* 新功能配置
*/
export interface NewFeatureConfig {
/** 配置项 1 */
option1: string;
/** 配置项 2 */
option2: number;
}
/**
* 新功能结果
*/
export interface NewFeatureResult {
/** 状态码 */
status: number;
/** 结果数据 */
data: string;
}
// 导出 Tauri 命令类型
export type NewFeatureCommands = {
execute_new_feature: (config: NewFeatureConfig) => Promise<NewFeatureResult>;
execute_new_feature_async: (config: NewFeatureConfig) => Promise<NewFeatureResult>;
};
步骤 11:编写测试
// src/services/new_feature_service.rs 中的测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_execute_with_valid_config() {
let service = NewFeatureService;
let config = NewFeatureConfig {
option1: "test".to_string(),
option2: 100,
};
let result = service.execute(&config).unwrap();
assert_eq!(result.status, 200);
}
#[test]
fn test_execute_with_empty_option1() {
let service = NewFeatureService;
let config = NewFeatureConfig {
option1: "".to_string(),
option2: 100,
};
assert!(service.execute(&config).is_err());
}
}
规范:
- ✅ 测试函数命名使用
test_前缀 - ✅ 测试正常场景和错误场景
- ✅ 使用
assert!和assert_eq!断言 - ✅ 运行
cargo test验证
步骤 12:验证和测试
# 1. 检查代码编译
cargo check
# 2. 运行测试
cargo test
# 3. 构建应用
pnpm build
# 4. 运行应用
pnpm tauri dev
# 5. 测试功能
# - 在前端界面测试新功能
# - 检查控制台输出
# - 验证错误处理
各层开发规范
Models 层规范
职责:定义数据结构,不包含业务逻辑
规范清单:
- ✅ 使用
serde的Serialize和Deserialize - ✅ 实现
Debug和Clone - ✅ 所有字段必须有文档注释
- ✅ 使用
new()方法构造复杂对象 - ✅ 字段类型优先使用基本类型
- ✅ 集中定义在一个模块中
示例:
/// 用户信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserInfo {
/// 用户 ID
pub id: u32,
/// 用户名
pub name: String,
}
impl UserInfo {
/// 创建新用户
pub fn new(id: u32, name: String) -> Self {
Self { id, name }
}
}
Utils 层规范
职责:提供纯函数算法,无副作用
规范清单:
- ✅ 纯函数,不依赖外部状态
- ✅ 不使用
unsafe代码 - ✅ 不执行 I/O 操作
- ✅ 包含单元测试
- ✅ 使用清晰的函数命名
示例:
/// 计算两点之间的距离
pub fn calculate_distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 {
let dx = x2 - x1;
let dy = y2 - y1;
(dx * dx + dy * dy).sqrt()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_distance() {
let dist = calculate_distance(0.0, 0.0, 3.0, 4.0);
assert_eq!(dist, 5.0);
}
}
Platform 层规范
职责:抽象平台差异,提供统一接口
规范清单:
- ✅ 使用 trait 定义接口
- ✅ 通过类型别名选择实现
- ✅ 提供所有平台的占位实现
- ✅ 使用
#[cfg(windows)]条件编译 - ✅ 占位实现返回
PlatformNotSupported
示例:
// trait 定义
pub trait FileAccessor {
fn read_file(&self, path: &str) -> AppResult<String>;
}
// Windows 实现
#[cfg(windows)]
pub type PlatformFile = WindowsFile;
// 占位实现
#[cfg(not(windows))]
pub type PlatformFile = DummyFile;
Service 层规范
职责:业务逻辑实现和流程编排
规范清单:
- ✅ 使用 struct 命名空间
- ✅ 所有方法返回
AppResult<T> - ✅ 参数验证在 Service 层进行
- ✅ 通过 trait 调用 Platform 层
- ✅ 可以调用 Utils 层函数
- ✅ 提供同步和异步版本(如需要)
- ✅ 使用详细的中文档注释
示例:
pub struct FileService;
impl FileService {
pub fn read_and_process(&self, path: &str) -> AppResult<String> {
// 1. 参数验证
if path.is_empty() {
return Err(AppError::InvalidData("路径不能为空".to_string()));
}
// 2. 调用 Platform 层
let content = PlatformFile::read_file(path)?;
// 3. 调用 Utils 层处理
let processed = utils::text::trim_whitespace(&content);
Ok(processed.to_string())
}
}
Command 层规范
职责:Tauri 命令处理,连接前端和 Service
规范清单:
- ✅ 使用
#[tauri::command]宏 - ✅ 返回
Result<T, String> - ✅ 参数使用结构体(便于扩展)
- ✅ 简洁的适配器代码
- ✅ 包含前端调用示例
- ✅ 错误转换为字符串
示例:
#[tauri::command]
pub fn process_file(path: String) -> Result<String, String> {
let service = FileService;
service
.read_and_process(&path)
.map_err(|e| e.to_string())
}
代码示例
完整示例:添加一个屏幕截图功能
1. 定义数据模型
// src/models/screenshot.rs
use serde::{Deserialize, Serialize};
/// 截图配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScreenshotConfig {
/// 是否包含光标
pub include_cursor: bool,
/// JPEG 质量 (1-100)
pub quality: u8,
}
/// 截图结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScreenshotResult {
/// 图片数据(Base64)
pub data: String,
/// 图片格式
pub format: String,
/// 图片宽度
pub width: u32,
/// 图片高度
pub height: u32,
}
2. 定义平台抽象
// src/platforms/screenshot.rs
use crate::error::AppResult;
use crate::models::screenshot::ScreenshotConfig;
/// 屏幕截图 trait
pub trait ScreenshotCapturer {
/// 截取整个屏幕
///
/// # 参数
///
/// * `config` - 截图配置
///
/// # 返回
///
/// 返回截图结果,包含 Base64 编码的图片数据
fn capture_screen(&self, config: &ScreenshotConfig) -> AppResult<ScreenshotResult>;
/// 截取指定区域
///
/// # 参数
///
/// * `x` - 起始 X 坐标
/// * `y` - 起始 Y 坐标
/// * `width` - 宽度
/// * `height` - 高度
/// * `config` - 截图配置
fn capture_region(
&self,
x: u32,
y: u32,
width: u32,
height: u32,
config: &ScreenshotConfig,
) -> AppResult<ScreenshotResult>;
}
// 类型别名
#[cfg(windows)]
pub type PlatformScreenshot = crate::platforms::windows::screenshot_impl::WindowsScreenshot;
#[cfg(not(windows))]
pub type PlatformScreenshot = crate::platforms::windows::screenshot_impl::DummyScreenshot;
3. 实现 Service
// src/services/screenshot_service.rs
//! 屏幕截图服务
//!
//! 提供屏幕截图功能
use crate::error::{AppError, AppResult};
use crate::models::screenshot::{ScreenshotConfig, ScreenshotResult};
use crate::platforms::screenshot::ScreenshotCapturer;
/// 截图服务
pub struct ScreenshotService;
impl ScreenshotService {
/// 截取屏幕
///
/// 根据配置截取屏幕画面
///
/// # 参数
///
/// * `config` - 截图配置
///
/// # 返回
///
/// 返回截图结果
pub fn capture(config: &ScreenshotConfig) -> AppResult<ScreenshotResult> {
// 验证配置
if config.quality < 1 || config.quality > 100 {
return Err(AppError::InvalidColorData(
"图片质量必须在 1-100 之间".to_string()
));
}
// 调用平台实现
PlatformScreenshot::capture_screen(config)
}
/// 截取指定区域
pub fn capture_region(
x: u32,
y: u32,
width: u32,
height: u32,
config: &ScreenshotConfig,
) -> AppResult<ScreenshotResult> {
if width == 0 || height == 0 {
return Err(AppError::InvalidColorData(
"宽度和高度必须大于 0".to_string()
));
}
PlatformScreenshot::capture_region(x, y, width, height, config)
}
}
4. 创建命令
// src/commands/screenshot_commands.rs
//! 截图命令
use crate::models::screenshot::{ScreenshotConfig, ScreenshotResult};
use crate::services::screenshot_service::ScreenshotService;
/// 截取屏幕命令
///
/// # 参数
///
/// * `config` - 截图配置
///
/// # 返回
///
/// 返回截图结果
///
/// # 前端调用示例
///
/// ```typescript
/// import { invoke } from '@tauri-apps/api/tauri';
///
/// const result = await invoke('capture_screen', {
/// config: {
/// include_cursor: false,
/// quality: 90
/// }
/// });
/// console.log(result.data); // Base64 图片数据
/// ```
#[tauri::command]
pub fn capture_screen(config: ScreenshotConfig) -> Result<ScreenshotResult, String> {
ScreenshotService::capture(&config).map_err(|e| e.to_string())
}
/// 截取区域命令
#[tauri::command]
pub fn capture_region(
x: u32,
y: u32,
width: u32,
height: u32,
config: ScreenshotConfig,
) -> Result<ScreenshotResult, String> {
ScreenshotService::capture_region(x, y, width, height, config)
.map_err(|e| e.to_string())
}
最佳实践
1. 命名规范
| 类型 | 命名风格 | 示例 |
|---|---|---|
| 模块 | snake_case | color_service.rs |
| 结构体 | PascalCase | ColorInfo, NewFeatureService |
| 函数 | snake_case | get_pixel_color, toggle_window |
| 常量 | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
| Trait | PascalCase + 能力 | ScreenAccessor, CursorController |
| 类型别名 | PascalCase + Platform/Type | PlatformScreen, AppResult |
2. 文档注释规范
/// 简短描述(一句话)
///
/// 详细描述(可以多行,说明功能、用途、注意事项)
///
/// # 参数
///
/// * `param1` - 参数说明
/// * `param2` - 参数说明
///
/// # 返回
///
/// 返回值说明
///
/// # 错误
///
/// - 错误类型1:错误场景
/// - 错误类型2:错误场景
///
/// # 示例
///
/// ```
/// let result = function_name(args);
/// assert!(result.is_ok());
/// ```
pub fn function_name(param1: Type1, param2: Type2) -> AppResult<ReturnType> {
// 实现
}
3. 错误处理规范
// ✅ 推荐:使用具体的错误类型
fn do_something() -> AppResult<()> {
if condition {
return Err(AppError::InvalidData("数据无效".to_string()));
}
Ok(())
}
// ❌ 不推荐:直接返回 String
fn do_something() -> Result<(), String> {
if condition {
return Err("错误".to_string());
}
Ok(())
}
4. 参数验证规范
// ✅ 在 Service 层验证参数
impl SomeService {
pub fn execute(&self, input: &str) -> AppResult<Output> {
// 参数验证
if input.is_empty() {
return Err(AppError::InvalidData("输入不能为空".to_string()));
}
if input.len() > 1000 {
return Err(AppError::InvalidData("输入过长".to_string()));
}
// 业务逻辑
// ...
}
}
5. 异步处理规范
// ✅ 提供 sync 和 async 两个版本
impl SomeService {
// 同步版本
pub fn execute(&self, input: &str) -> AppResult<Output> {
// 直接调用
}
// 异步版本
pub async fn execute_async(&self, input: String) -> AppResult<Output> {
// 使用 async/await
tokio::time::sleep(Duration::from_secs(1)).await;
self.execute(&input)
}
}
6. 平台检测规范
// ✅ 使用条件编译和 trait
#[cfg(windows)]
fn platform_specific() -> AppResult<()> {
WindowsImpl::do_something()
}
#[cfg(not(windows))]
fn platform_specific() -> AppResult<()> {
Err(AppError::PlatformNotSupported(
"此平台暂不支持".to_string()
))
}
// ❌ 不推荐:运行时检测
fn platform_specific() -> AppResult<()> {
if cfg!(windows) {
// Windows 代码
} else {
Err(AppError::PlatformNotSupported("...".to_string()))
}
}
7. 代码组织规范
// ✅ 推荐:按功能分组
pub struct ColorService;
impl ColorService {
// 公共方法
pub fn new() -> Self { Self }
pub fn do_work(&self) -> AppResult<()> { }
// 私有辅助方法
fn validate(&self) -> AppResult<()> { }
fn process(&self) -> AppResult<()> { }
}
// ✅ 使用 mod 组织相关功能
mod color_conversion {
pub fn rgb_to_hsl() { }
pub fn hsl_to_rgb() { }
}
测试规范
单元测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normal_case() {
// 测试正常场景
let result = function_under_test(normal_input);
assert_eq!(result, expected);
}
#[test]
fn test_edge_case() {
// 测试边界条件
let result = function_under_test(edge_input);
assert!(result.is_ok());
}
#[test]
fn test_error_case() {
// 测试错误场景
let result = function_under_test(invalid_input);
assert!(result.is_err());
}
}
集成测试
// tests/integration_test.rs
#[test]
fn test_full_workflow() {
// 测试完整的业务流程
let service = MyService::new();
let config = MyConfig::default();
let result = service.execute(&config).unwrap();
assert_eq!(result.status, 200);
}
运行测试
# 运行所有测试
cargo test
# 运行特定测试
cargo test test_color_conversion
# 运行测试并显示输出
cargo test -- --nocapture
# 运行测试并生成文档
cargo test --doc
常见问题
Q: 如何添加新的错误类型?
A: 在 error.rs 中添加新的枚举变体,并在 Display 实现中添加处理:
pub enum AppError {
// ...
NewErrorType(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
// ...
AppError::NewErrorType(msg) => write!(f, "新错误: {}", msg),
}
}
}
Q: 如何在多个平台实现同一个功能?
A: 为每个平台创建独立的实现文件,并通过条件编译选择:
// platforms/windows/impl.rs
#[cfg(windows)]
pub struct PlatformImpl;
impl PlatformTrait for PlatformImpl { }
// platforms/macos/impl.rs
#[cfg(target_os = "macos")]
pub struct PlatformImpl;
impl PlatformTrait for PlatformImpl { }
// platforms/mod.rs
#[cfg(windows)]
pub type Platform = crate::platforms::windows::impl::PlatformImpl;
#[cfg(target_os = "macos")]
pub type Platform = crate::platforms::macos::impl::PlatformImpl;
Q: 如何处理异步操作?
A: 在 Service 层提供 async 函数,Command 层使用 async 命令:
// Service
pub async fn fetch_data(&self) -> AppResult<Data> {
// 异步操作
}
// Command
#[tauri::command]
pub async fn get_data() -> Result<Data, String> {
service.fetch_data().await.map_err(|e| e.to_string())
}
检查清单
在提交代码前,确保:
- 代码符合 Rust 格式规范(
cargo fmt --check) - 代码通过 clippy 检查(
cargo clippy) - 所有测试通过(
cargo test) - 编译成功(
cargo check) - 所有公开 API 都有文档注释
- 文档注释包含示例代码
- 错误消息使用中文
- 遵循依赖原则(上层依赖下层)
- 平台特定代码正确使用条件编译
- 新增类型已导出(如需要)
- 命令已在
lib.rs中注册