use reqwest::Error as ReqwestError;
use serde::de::DeserializeOwned;
use serde_json::Error as JsonError;
// 定义一个枚举来统一处理不同类型的错误
#[derive(Debug)]
enum DownloadError {
Network(ReqwestError),
Json(JsonError),
}
impl From<ReqwestError> for DownloadError {
fn from(e: ReqwestError) -> Self {
DownloadError::Network(e)
}
}
impl From<JsonError> for DownloadError {
fn from(e: JsonError) -> Self {
DownloadError::Json(e)
}
}
// 异步函数,接受URL字符串作为参数,返回解析后的数据
async fn download_and_parse<T: DeserializeOwned>(url: &str) -> Result<T, DownloadError> {
let client = reqwest::Client::new();
let response = client.get(url).send().await?;
let data = response.json::<T>().await?;
Ok(data)
}
错误处理
- 网络错误:使用
reqwest
库进行HTTP请求,send
方法返回Result
类型,当发生网络错误时会返回Err
,我们通过?
操作符将ReqwestError
转换为DownloadError::Network
。
- 解析错误:使用
response.json::<T>()
解析JSON数据,当解析失败时会返回Err
,我们通过?
操作符将JsonError
转换为DownloadError::Json
。
资源释放
reqwest::Client
是可复用的,在函数结束时会自动释放资源。
response
在解析完成后,其占用的资源也会被正确释放,因为json
方法会消费response
。
异步函数执行流程与普通函数的不同
- 普通函数:按顺序依次执行,遇到函数调用会阻塞当前线程直到被调用函数返回。函数执行过程中不会被其他任务打断,除非发生中断或异常。
- 异步函数:
- 非阻塞执行:异步函数在执行到
await
关键字时,会暂停当前函数的执行,将控制权交回给调用者(通常是事件循环),允许其他异步任务继续执行。当await
的任务完成时,异步函数会从暂停的地方继续执行。
- 异步任务调度:异步函数内部的任务由异步运行时(如
tokio
)进行调度管理。运行时会在多个异步任务之间切换执行,以充分利用CPU资源,实现高效的并发执行。
- 状态机生成:Rust编译器会将异步函数编译为状态机,状态机通过枚举来表示函数的不同执行状态,以此来管理函数的暂停和恢复执行。