generics - 从可转换为多种类型的函数返回值
问题描述
在我的库中,我调用了一个 REST API,因此有一个通用的反序列化功能。Result<T,E>
由于整个过程可能会失败,因此该函数返回 a 是正确的。如果该过程成功完成,我将返回另一个Result<T, E>
whereOk(T)
指示服务器返回 2xx 状态代码并Err(E)
指示 4xx 或 5xx 错误。对于 API 可以返回的每个错误(每个请求都有多种可能性),我拥有,或者更确切地说:想要拥有一个包含错误和有关请求的附加信息的结构。现在,我可以返回一个泛型ErrorResponse
而不是E
,然后让调用者通过 `From 转换它,但这意味着我没有使用 Rust 的强类型系统和泛型,所以我宁愿避免这种情况。
我想知道的是:我需要替换什么E
才能自动反序列化为正确的错误(基于状态码标头)?我已经尝试过使用impl From<ErrorResponse>
,但这似乎不起作用。
我的反序列化函数目前看起来像这样:
pub type DeserializationResult<T> = Result<APIResult<T>, DeserializationError>;
pub type APIResult<T> = Result<DataResponse<T>, ErrorResponse>;
// What to change here? -------------^
// I want to get rid of this
#[derive(Debug)]
pub(crate) struct ErrorResponse {
pub headers: reqwest::header::HeaderMap,
pub status_code: reqwest::StatusCode,
pub message: Option<String>,
// Additional fields removed for brevity
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ErrorDetails {
pub id: String,
pub status: u16,
pub title: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<String>,
}
#[derive(Error, Debug)]
pub enum DeserializationError {
// Errors that can occur during deserialization, e.g. "serde_json::Error"
}
pub async fn deserialize_response<T>(response: Response) -> DeserializationResult<T>
where T: DeserializeOwned,
{
let status_code = response.status();
let headers = response.headers().clone();
let content = response.text().await?;
if !status_code.is_client_error() && !status_code.is_server_error() {
let success_result: T = serde_json::from_str(&content)?;
let data_response = DataResponse {
status_code,
headers,
content: success_result,
};
let inner_data = Ok(data_response);
Ok(inner_data)
} else {
let error_result = serde_json::from_str(&content)?;
let s = StatusCode::from_u16(error_result.status).map_err(|_| DeserializationError::InvalidError)?;
let error_response = ErrorResponse {
headers,
status_code,
message: error_result.detail.clone(),
};
let inner_error = Err(error_response);
Ok(inner_error)
}
}
我想这样调用函数:
let de = deserialization::deserialize_response(server_response).await?;
match de {
Ok(data_response) => {
// Some additional conversion steps
Ok(data)
}
Err(e)=> {
match e.status_code.as_u16() {
// Currently the error is manually converted here
}
}
}
我想要的甚至是可能的,还是我需要像现在一样手动转换错误?