第七章:高级特性与项目优化
教学目标
- 掌握 Rust 命令行参数解析库 clap 的使用,实现更专业的命令行接口
- 理解异步编程模型,掌握 tokio 库的 async/await 语法与异步操作
- 掌握 Rust 并发编程基础,包括线程创建、共享数据安全访问
- 运用高级特性优化 RustTask 项目,提升用户体验与系统性能
核心知识点
1. 命令行参数解析
clap 库基础用法
clap 是 Rust 中最流行的命令行解析库,支持复杂的命令行接口设计,包括子命令、参数验证、帮助信息生成等。
rust
# Cargo.toml
[dependencies]
clap = { version = "4.4", features = ["derive"] }
rust
use clap::Parser;
// 使用derive宏定义命令行参数结构
#[derive(Parser, Debug)]
#[clap(author, version, about = "RustTask - 命令行任务管理工具")]
struct Args {
/// 任务标题
#[clap(short, long)]
title: String,
/// 任务描述
#[clap(short, long)]
description: String,
/// 截止日期,格式为YYYY-MM-DD
#[clap(short, long, default_value = "today")]
due: String,
/// 显示详细信息
#[clap(short, long)]
verbose: bool,
}
fn main() {
let args = Args::parse();
println!("任务标题: {}", args.title);
println!("任务描述: {}", args.description);
println!("截止日期: {}", args.due);
println!("详细模式: {}", args.verbose);
}
子命令与命令行层级结构
clap 支持定义子命令,使命令行接口更清晰,适合复杂的应用程序。
rust
use clap::Parser;
#[derive(Parser, Debug)]
#[clap(author, version, about = "RustTask - 命令行任务管理工具")]
enum Command {
/// 添加新任务
Add {
title: String,
description: String,
#[clap(short, long, default_value = "today")]
due: String,
},
/// 列出所有任务
List {
#[clap(short, long, possible_values = &["todo", "in-progress", "completed"])]
status: Option<String>,
},
/// 更新任务状态
Update {
id: u32,
#[clap(short, long, possible_values = &["todo", "in-progress", "completed"])]
status: String,
},
/// 删除任务
Delete {
id: u32,
#[clap(short, long, default_value = "false")]
force: bool,
},
}
fn main() {
let command = Command::parse();
match command {
Command::Add { title, description, due } => {
println!("添加任务: {} - {}", title, description);
println!("截止日期: {}", due);
},
Command::List { status } => {
println!("列出任务");
if let Some(status) = status {
println!("筛选状态: {}", status);
}
},
Command::Update { id, status } => {
println!("更新任务 {} 状态为: {}", id, status);
},
Command::Delete { id, force } => {
if force {
println!("强制删除任务 {}", id);
} else {
println!("确认删除任务 {} (y/n)?", id);
// 处理确认逻辑
}
},
}
}
自定义帮助信息与验证
clap 支持自定义帮助信息和参数验证,提升用户体验。
rust
use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[clap(
author = "RustTask 团队",
version = "1.0.0",
about = "高效的命令行任务管理工具",
long_about = None, // 不显示详细帮助
)]
struct Args {
/// 配置文件路径
#[clap(short, long, value_parser, default_value = "config.toml")]
config: PathBuf,
/// 日志级别
#[clap(
short,
long,
value_enum,
possible_values = &["debug", "info", "warn", "error"],
default_value = "info"
)]
log_level: String,
/// 运行模式
#[clap(
short,
long,
value_parser,
possible_values = &["interactive", "batch", "daemon"],
required = true
)]
mode: String,
}
// 自定义参数验证
fn validate_mode(mode: &str) -> Result<(), String> {
match mode {
"interactive" | "batch" | "daemon" => Ok(()),
_ => Err("无效的运行模式,必须为 interactive、batch 或 daemon".to_string()),
}
}
fn main() {
let args = Args::parse();
println!("配置文件: {}", args.config.display());
println!("日志级别: {}", args.log_level);
println!("运行模式: {}", args.mode);
}
2. 异步编程
tokio 运行时与异步函数
tokio 是 Rust 中最常用的异步运行时,支持非阻塞 IO 和异步任务调度。
rust
# Cargo.toml
[dependencies]
tokio = { version = "1.32", features = ["full"] }
rust
use tokio::time::{sleep, Duration};
// 异步函数,必须在异步上下文中调用
async fn async_greeting() {
println!("开始异步任务");
// 非阻塞睡眠,不阻塞线程
sleep(Duration::from_secs(1)).await;
println!("异步任务完成");
}
fn main() {
// 运行异步函数
tokio::runtime::Runtime::new()
.unwrap()
.block_on(async_greeting());
println!("主线程继续执行");
}
async/await 语法与 Future
async/await 是 Rust 异步编程的核心语法,允许编写类似同步的异步代码。
rust
use tokio::time::{sleep, Duration};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::net::TcpListener;
// 异步函数返回Future
async fn fetch_data() -> Result<String, Box<dyn std::error::Error>> {
// 模拟网络请求
sleep(Duration::from_secs(1)).await;
Ok("数据已获取".to_string())
}
// 多个异步任务并发执行
async fn concurrent_tasks() -> Result<(), Box<dyn std::error::Error>> {
// 创建两个异步任务
let task1 = fetch_data();
let task2 = fetch_data();
// 并发执行任务
let result1 = task1.await?;
let result2 = task2.await?;
println!("任务1结果: {}", result1);
println!("任务2结果: {}", result2);
Ok(())
}
// 异步TCP服务器
async fn tcp_server() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
println!("服务器启动,监听127.0.0.1:8080");
loop {
let (mut socket, _) = listener.accept().await?;
println!("新连接已建立");
// 处理客户端连接
tokio::spawn(async move {
let mut buffer = [0; 1024];
if let Ok(bytes_read) = socket.read(&mut buffer).await {
if bytes_read > 0 {
println!("收到数据: {:?}", &buffer[0..bytes_read]);
socket.write_all(b"Hello from Rust!").await.unwrap();
}
}
});
}
}
异步文件操作与流处理
tokio 提供了异步文件操作 API,适合处理 IO 密集型任务。
rust
use tokio::fs::{read_to_string, write};
use tokio::stream::StreamExt;
// 异步读取文件
async fn read_file(path: &str) -> Result<String, std::io::Error> {
read_to_string(path).await
}
// 异步写入文件
async fn write_file(path: &str, content: &str) -> Result<(), std::io::Error> {
write(path, content).await
}
// 处理文件流
async fn process_files() -> Result<(), std::io::Error> {
// 读取多个文件并处理
let file1 = read_file("file1.txt").await?;
let file2 = read_file("file2.txt").await?;
let result = file1 + &file2;
write_file("combined.txt", &result).await?;
println!("文件处理完成");
Ok(())
}
// 处理数据流
async fn process_stream() {
// 创建一个包含1-10的流
let stream = tokio::stream::iter(1..=10);
// 异步遍历流
let mut stream = stream;
while let Some(item) = stream.next().await {
println!("处理项目: {}", item);
// 模拟处理时间
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
}
}
3. 并发编程
线程创建与管理
Rust 的标准库提供了轻量级线程,支持跨平台的线程创建与管理。
rust
use std::thread;
use std::time::Duration;
fn main() {
// 创建新线程
let thread = thread::spawn(|| {
println!("子线程开始执行");
thread::sleep(Duration::from_secs(1));
println!("子线程执行完毕");
});
println!("主线程继续执行");
// 等待子线程完成
thread.join().unwrap();
println!("所有线程执行完毕");
}
// 带返回值的线程
fn thread_with_result() {
let result = thread::spawn(|| {
println!("计算中...");
thread::sleep(Duration::from_secs(1));
10 * 2
}).join().unwrap();
println!("计算结果: {}", result);
}
// 线程局部存储
fn thread_local_storage() {
thread_local! {
static COUNTER: u32 = 0;
}
// 多个线程共享thread_local变量
let handles = (0..5).map(|i| {
thread::spawn(move || {
COUNTER.with(|c| {
*c += 1;
println!("线程 {}: COUNTER = {}", i, c);
});
})
}).collect::<Vec<_>>();
for handle in handles {
handle.join().unwrap();
}
}
共享数据并发访问
Rust 提供了Mutex和Arc用于安全地在多个线程间共享可变数据。
rust
use std::sync::{Mutex, Arc};
use std::thread;
fn main() {
// Arc<Mutex<T>> 用于在多个线程间共享可变数据
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for i in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut count = counter.lock().unwrap();
*count += 1;
println!("线程 {}: 计数器 = {}", i, *count);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最终计数器值: {}", *counter.lock().unwrap());
}
// 读写锁示例
fn read_write_lock() {
use std::sync::{RwLock, Arc};
use std::thread;
let data = Arc::new(RwLock::new(String::from("初始数据")));
let mut handles = vec![];
// 创建10个读线程
for i in 0..10 {
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
let read_lock = data.read().unwrap();
println!("读线程 {}: 数据 = {}", i, read_lock);
});
handles.push(handle);
}
// 创建1个写线程
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut write_lock = data.write().unwrap();
*write_lock = "更新后的数据".to_string();
println!("写线程: 数据已更新");
});
handles.push(handle);
for handle in handles {
handle.join().unwrap();
}
println!("最终数据: {}", *data.read().unwrap());
}
通道与线程间通信
mpsc(多生产者单消费者)通道用于线程间安全地传递数据。
rust
use std::thread;
use std::time::Duration;
use std::sync::mpsc;
fn main() {
// 创建通道
let (sender, receiver) = mpsc::channel();
// 生产者线程
let producer = thread::spawn(move || {
for i in 0..5 {
sender.send(i).unwrap();
println!("生产者发送: {}", i);
thread::sleep(Duration::from_secs(1));
}
});
// 消费者线程
let consumer = thread::spawn(move || {
for message in receiver {
println!("消费者接收: {}", message);
}
});
// 等待生产者完成
producer.join().unwrap();
// 关闭通道,消费者将退出
drop(sender);
consumer.join().unwrap();
}
// 多生产者单消费者通道
fn multiple_producers() {
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
let (sender, receiver) = mpsc::channel();
let senders = (0..3).map(|i| {
let sender = mpsc::Sender::clone(&sender);
thread::spawn(move || {
for j in 0..3 {
sender.send((i, j)).unwrap();
thread::sleep(Duration::from_millis(500));
}
})
}).collect::<Vec<_>>();
// 消费所有消息
for _ in 0..9 {
if let Ok((producer, message)) = receiver.recv() {
println!("接收来自生产者 {} 的消息: {}", producer, message);
}
}
// 等待所有生产者完成
for sender in senders {
sender.join().unwrap();
}
}
// 异步通道
async fn async_channel() {
use tokio::sync::mpsc;
use tokio::time::Duration;
// 创建异步通道
let (sender, mut receiver) = mpsc::channel(10);
// 生产者任务
tokio::spawn(async move {
for i in 0..5 {
sender.send(i).await.unwrap();
println!("异步生产者发送: {}", i);
tokio::time::sleep(Duration::from_secs(1)).await;
}
});
// 消费者任务
tokio::spawn(async move {
while let Some(message) = receiver.recv().await {
println!("异步消费者接收: {}", message);
}
});
// 等待一段时间
tokio::time::sleep(Duration::from_secs(6)).await;
}
项目实战:RustTask 高级特性优化
1. 用 clap 重构命令行界面
使用 clap 库重新设计 RustTask 的命令行接口,实现更专业的命令行交互。
rust
// src/main.rs
mod task;
mod cli;
mod storage;
use clap::Parser;
use cli::TaskManager;
use storage::{FileStorage, TaskStorage};
use task::TaskStatus;
use std::path::PathBuf;
use std::time::SystemTime;
// 定义命令行子命令
#[derive(Parser, Debug)]
#[clap(author, version, about = "RustTask - 高效的命令行任务管理工具")]
enum Command {
/// 添加新任务
Add {
/// 任务标题
#[clap(short, long)]
title: String,
/// 任务描述
#[clap(short, long)]
description: String,
/// 截止日期 (YYYY-MM-DD)
#[clap(short, long, default_value = "today")]
due: String,
},
/// 列出所有任务
List {
/// 按状态筛选
#[clap(short, long, possible_values = &["todo", "in-progress", "completed"])]
status: Option<String>,
},
/// 更新任务状态
Update {
/// 任务ID
#[clap(short, long)]
id: u32,
/// 新状态
#[clap(short, long, possible_values = &["todo", "in-progress", "completed"])]
status: String,
},
/// 删除任务
Delete {
/// 任务ID
#[clap(short, long)]
id: u32,
/// 强制删除,不提示确认
#[clap(short, long, default_value = "false")]
force: bool,
},
}
fn main() {
// 解析命令行参数
let command = Command::parse();
let storage_path = PathBuf::from("tasks.json");
let storage = FileStorage::new(storage_path.clone());
// 初始化任务管理器
let mut manager = match TaskManager::new(storage) {
Ok(manager) => manager,
Err(e) => {
eprintln!("初始化任务管理器失败: {}", e);
return;
}
};
// 处理不同命令
match command {
Command::Add { title, description, due } => {
// 解析截止日期(简化处理)
let due_date = match due.as_str() {
"today" => SystemTime::now() + std::time::Duration::from_secs(86400),
_ => {
// 实际项目中应解析日期字符串
SystemTime::now() + std::time::Duration::from_secs(86400)
}
};
manager.add_task(title, description, due_date);
if let Err(e) = manager.save() {
eprintln!("保存任务失败: {}", e);
}
},
Command::List { status } => {
manager.list_tasks();
},
Command::Update { id, status } => {
let status = match status.as_str() {
"todo" => TaskStatus::Todo,
"in-progress" => TaskStatus::InProgress,
"completed" => TaskStatus::Completed,
_ => {
eprintln!("无效状态");
return;
}
};
manager.update_task_status(id, status);
if let Err(e) = manager.save() {
eprintln!("保存任务失败: {}", e);
}
},
Command::Delete { id, force } => {
if !force {
println!("确认删除任务 {}? (y/n)", id);
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
if input.trim() != "y" {
println!("取消删除");
return;
}
}
if let Err(e) = manager.remove_task(id) {
eprintln!("删除任务失败: {}", e);
} else {
println!("任务已删除");
if let Err(e) = manager.save() {
eprintln!("保存任务失败: {}", e);
}
}
},
}
}
2. 实现异步文件存储
使用 tokio 库重构存储模块,实现异步文件操作,提升 IO 性能。
rust
// src/storage.rs
use crate::task::{Task, TaskStatus};
use std::collections::HashMap;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tokio::fs::{File, OpenOptions};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::error::Error;
// 定义存储接口
pub trait TaskStorage {
type Error: std::error::Error;
async fn save(&self, tasks: &HashMap<u32, Task>, next_id: u32) -> Result<(), Self::Error>;
async fn load(&self) -> Result<(HashMap<u32, Task>, u32), Self::Error>;
}
// 存储错误类型
#[derive(Error, Debug)]
pub enum StorageError {
#[error("文件操作错误: {0}")]
FileError(#[from] tokio::io::Error),
#[error("JSON解析错误: {0}")]
JsonError(#[from] serde_json::Error),
#[error("任务数据格式错误: {0}")]
DataFormatError(String),
}
// 序列化任务数据
#[derive(Serialize, Deserialize, Debug)]
struct TaskStorageData {
tasks: HashMap<u32, Task>,
next_id: u32,
}
// 异步文件存储实现
pub struct AsyncFileStorage {
path: PathBuf,
}
impl AsyncFileStorage {
pub fn new(path: impl Into<PathBuf>) -> Self {
AsyncFileStorage { path: path.into() }
}
}
impl TaskStorage for AsyncFileStorage {
type Error = StorageError;
async fn save(&self, tasks: &HashMap<u32, Task>, next_id: u32) -> Result<(), Self::Error> {
let storage = TaskStorageData {
tasks: tasks.clone(),
next_id,
};
// 序列化为JSON
let data = serde_json::to_vec(&storage)?;
// 异步写入文件
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&self.path)
.await?;
file.write_all(&data).await?;
Ok(())
}
async fn load(&self) -> Result<(HashMap<u32, Task>, u32), Self::Error> {
// 文件不存在时返回空集合
if !self.path.exists() {
return Ok((HashMap::new(), 1));
}
// 异步读取文件
let mut file = File::open(&self.path).await?;
let mut data = Vec::new();
file.read_to_end(&mut data).await?;
// 反序列化JSON
let storage: TaskStorageData = serde_json::from_slice(&data)?;
Ok((storage.tasks, storage.next_id))
}
}
3. 添加任务到期提醒的并发功能
使用线程和通道实现任务到期提醒功能。
rust
// src/cli.rs
use crate::storage::TaskStorage;
use crate::task::{Task, TaskStatus};
use std::collections::HashMap;
use std::time::{SystemTime, Duration};
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc;
pub struct TaskManager<S> {
tasks: Arc<Mutex<HashMap<u32, Task>>>,
next_id: u32,
storage: S,
reminder_thread: Option<thread::JoinHandle<()>>,
}
impl<S: TaskStorage> TaskManager<S> {
pub async fn new(storage: S) -> Result<Self, S::Error> {
let (tasks, next_id) = storage.load().await?;
let tasks = Arc::new(Mutex::new(tasks));
let manager = Self {
tasks,
next_id,
storage,
reminder_thread: None,
};
// 启动提醒线程
manager.start_reminder_thread();
Ok(manager)
}
// 启动任务提醒线程
fn start_reminder_thread(&mut self) {
let tasks = Arc::clone(&self.tasks);
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
println!("任务提醒线程已启动");
loop {
// 检查到期任务
let tasks = tasks.lock().unwrap();
let now = SystemTime::now();
for (id, task) in &*tasks {
if task.status == TaskStatus::Todo {
if let Ok(dur) = task.due_date.duration_since(now) {
if dur < Duration::from_secs(86400) { // 24小时内到期
sender.send((id.clone(), task.title.clone())).unwrap();
}
}
}
}
// 每秒检查一次
thread::sleep(Duration::from_secs(1));
}
});
self.reminder_thread = Some(handle);
}
// 添加任务
pub fn add_task(&mut self, title: String, description: String, due_date: SystemTime) {
let mut tasks = self.tasks.lock().unwrap();
let task = Task::new(self.next_id, title, description, due_date);
tasks.insert(self.next_id, task);
println!("任务已添加,ID: {}", self.next_id);
self.next_id += 1;
}
// 列出任务
pub fn list_tasks(&self) {
let tasks = self.tasks.lock().unwrap();
if tasks.is_empty() {
println!("暂无任务");
return;
}
println!("ID\t状态\t标题\t\t截止日期");
println!("----------------------------------------");
for (_, task) in tasks {
let status = match task.status {
TaskStatus::Todo => "待办",
TaskStatus::InProgress => "进行中",
TaskStatus::Completed => "已完成",
};
let due_date = match task.due_date.duration_since(SystemTime::UNIX_EPOCH) {
Ok(dur) => format!("{}", dur.as_secs()),
Err(_) => "未知日期".to_string(),
};
println!("{}\t{}\t{}\t{}", task.id, status, task.title, due_date);
}
}
// 更新任务状态
pub fn update_task_status(&mut self, task_id: u32, status: TaskStatus) {
let mut tasks = self.tasks.lock().unwrap();
if let Some(task) = tasks.get_mut(&task_id) {
task.update_status(status);
println!("任务状态已更新");
} else {
println!("未找到 ID 为 {} 的任务", task_id);
}
}
// 删除任务
pub fn remove_task(&mut self, task_id: u32) -> Result<(), &'static str> {
let mut tasks = self.tasks.lock().unwrap();
if tasks.remove(&task_id).is_none() {
Err("任务不存在")
} else {
Ok(())
}
}
// 保存任务
pub async fn save(&self) -> Result<(), S::Error> {
let tasks = self.tasks.lock().unwrap();
self.storage.save(tasks, self.next_id).await
}
}
4. 整合所有优化并测试
更新 main.rs 以使用异步存储和 clap 命令行接口,并测试新功能。
rust
// src/main.rs
mod task;
mod cli;
mod storage;
use cli::TaskManager;
use storage::AsyncFileStorage;
use task::TaskStatus;
use clap::Parser;
use std::path::PathBuf;
use std::time::SystemTime;
use tokio::runtime::Runtime;
// 命令行参数定义
#[derive(Parser, Debug)]
#[clap(author, version, about = "RustTask - 高效的命令行任务管理工具")]
enum Command {
Add {
title: String,
description: String,
#[clap(short, long, default_value = "today")]
due: String,
},
List,
Update {
id: u32,
status: String,
},
Delete {
id: u32,
#[clap(short, long, default_value = "false")]
force: bool,
},
}
fn main() {
// 初始化Tokio运行时
let runtime = Runtime::new().unwrap();
// 解析命令行参数
let command = Command::parse();
let storage_path = PathBuf::from("tasks.json");
let storage = AsyncFileStorage::new(storage_path.clone());
// 运行异步任务管理器初始化
let manager = runtime.block_on(TaskManager::new(storage));
let mut manager = match manager {
Ok(manager) => manager,
Err(e) => {
eprintln!("初始化任务管理器失败: {}", e);
return;
}
};
// 处理命令
match command {
Command::Add { title, description, due } => {
let due_date = match due.as_str() {
"today" => SystemTime::now() + std::time::Duration::from_secs(86400),
_ => SystemTime::now() + std::time::Duration::from_secs(86400),
};
manager.add_task(title, description, due_date);
runtime.block_on(manager.save()).unwrap();
},
Command::List => {
manager.list_tasks();
},
Command::Update { id, status } => {
let status = match status.as_str() {
"todo" => TaskStatus::Todo,
"in-progress" => TaskStatus::InProgress,
"completed" => TaskStatus::Completed,
_ => {
eprintln!("无效状态");
return;
}
};
manager.update_task_status(id, status);
runtime.block_on(manager.save()).unwrap();
},
Command::Delete { id, force } => {
if !force {
println!("确认删除任务 {}? (y/n)", id);
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
if input.trim() != "y" {
println!("取消删除");
return;
}
}
if let Err(e) = manager.remove_task(id) {
eprintln!("删除任务失败: {}", e);
} else {
println!("任务已删除");
runtime.block_on(manager.save()).unwrap();
}
},
}
}
实践作业
为 RustTask 添加网络同步功能,使用异步 HTTP 客户端实现任务数据的云端同步,具体要求:
- 添加sync子命令,用于同步任务数据
- 使用reqwest库实现异步 HTTP 请求
- 定义云端 API 接口,支持任务的增删改查
- 实现本地与云端任务数据的合并逻辑
- 处理网络错误与数据冲突
rust
# Cargo.toml
[dependencies]
reqwest = { version = "0.11", features = ["json", "async-std"] }
async-std = { version = "1.12", features = ["runtime"] }
rust
// src/storage.rs
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use tokio::time::Duration;
// 云端任务数据结构
#[derive(Serialize, Deserialize, Debug)]
struct CloudTask {
id: u32,
title: String,
description: String,
due_date: u64,
status: String,
}
// 云端存储实现
pub struct CloudStorage {
base_url: String,
client: Client,
}
impl CloudStorage {
pub fn new(base_url: String) -> Result<Self, Box<dyn Error>> {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()?;
Ok(CloudStorage { base_url, client })
}
}
impl TaskStorage for CloudStorage {
type Error = Box<dyn Error>;
async fn save(&self, tasks: &HashMap<u32, Task>, next_id: u32) -> Result<(), Self::Error> {
// 转换为云端任务格式
let cloud_tasks = tasks.values().map(|task| {
CloudTask {
id: task.id,
title: task.title.clone(),
description: task.description.clone(),
due_date: task.due_date.duration_since(SystemTime::UNIX_EPOCH)?.as_secs(),
status: match task.status {
TaskStatus::Todo => "todo".to_string(),
TaskStatus::InProgress => "in-progress".to_string(),
TaskStatus::Completed => "completed".to_string(),
},
}
}).collect::<Vec<_>>();
// 发送PUT请求同步任务
self.client.put(format!("{}/tasks", self.base_url))
.json(&cloud_tasks)
.send()
.await?
.error_for_status()?;
Ok(())
}
async fn load(&self) -> Result<(HashMap<u32, Task>, u32), Self::Error> {
// 发送GET请求获取云端任务
let cloud_tasks: Vec<CloudTask> = self.client.get(format!("{}/tasks", self.base_url))
.send()
.await?
.error_for_status()?
.json()
.await?;
// 转换为本地任务格式
let mut tasks = HashMap::new();
let mut next_id = 1;
for cloud_task in cloud_tasks {
let status = match cloud_task.status.as_str() {
"todo" => TaskStatus::Todo,
"in-progress" => TaskStatus::InProgress,
"completed" => TaskStatus::Completed,
_ => TaskStatus::Todo,
};
let due_date = SystemTime::UNIX_EPOCH + Duration::from_secs(cloud_task.due_date);
tasks.insert(cloud_task.id, Task::new(
cloud_task.id,
cloud_task.title,
cloud_task.description,
due_date,
));
if cloud_task.id >= next_id {
next_id = cloud_task.id + 1;
}
}
Ok((tasks, next_id))
}
}
通过完成这个作业,你将综合运用异步编程、并发编程和网络编程等高级特性,进一步提升 Rust 项目开发能力,理解如何构建具有网络功能的复杂应用程序。