[英]How can I return something meaningful from a generic function if there is nothing to return?
我正在Rust中建立一个具有send
方法的库,该方法使用reqwest对本地RPC服务器执行HTTP请求。
此方法在Result
中返回通用类型R
,其中R: DeserializeOwned
。 在为每个响应做出正确的类型之后, serde_json::from_str()
可以为我获取类型。
如果对请求没有响应,如何使send
仍然返回有意义的内容?
这是我现在拥有的代码:
fn send<R, T>(
&self,
request: &RpcRequest<T>,
) -> Result<R, ApiError>
where
T: Serialize + Debug,
R: DeserializeOwned + Debug,
let res = serde_json::from_str(&buf).map_err(|err| ClientError::Json(err))
现在,我被迫创建并返回一个Err
,但是从技术上讲,不返回任何请求的请求是预期的行为,因此我想返回一个Err
以外的东西。
我尝试通过用Option
包裹R
来解决此问题,但这意味着我必须对每个响应进行两次包装,并且reqwest的98%的响应中都包含数据,因此感觉有点过头了。
我还尝试返回一个自制的EmptyResponse
类型,但是编译器抱怨: expected type R, found type EmptyResponse
。 我想返回类型EmptyResponse
将是我想要的,但是也许有人可以提供一些技巧,说明如何做得更好。
您可以如文档中所示返回Result<Option<R>, ApiError>
,然后像这样进行匹配:
match sender.send(request) {
Ok(Some(r)) => {
// process response
}
Ok(None) => {
// process empty response
}
Err(e) => {
// process error
}
}
// or
if let Ok(Some(r)) = sender.send(request) {
// process response
}
我尝试通过用
Option
包裹R
来解决此问题,但这意味着我必须对每个响应进行两次包装,并且reqwest的98%的响应中都包含数据,因此感觉有点过头了。
解开Option
是非常便宜的操作,无需担心。
务实的答案是具有两个功能:
fn send<R, T>(&self, request: &RpcRequest<T>) -> Result<R, ApiError>
where
T: Serialize + Debug,
R: DeserializeOwned + Debug,
fn send_no_response<T>(&self, request: &RpcRequest<T>) -> Result<(), ApiError>
where
T: Serialize + Debug,
如果服务器碰巧返回一个可以反序列化为type ()
,则可以避免两个函数的开销。 但是,JSON 不是最常见的格式之一:
use serde::de::DeserializeOwned; // 1.0.85
use serde_json; // 1.0.37
type Error = Box<std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
fn send<R>() -> Result<R, Error>
where
R: DeserializeOwned,
{
serde_json::from_str("").map_err(Into::into)
}
fn main() {
let _r: () = send().expect("Unable to deserialize");
}
恐慌:
Unable to deserialize: Error("EOF while parsing a value", line: 1, column: 0)
在一个专业化的世界中,您可以使用它和一个辅助特性来简化为一个功能:
#![feature(specialization)]
use serde::de::DeserializeOwned; // 1.0.85
use serde_json; // 1.0.37
type Error = Box<std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
type ApiResponse = &'static str;
trait FromApi: Sized {
fn convert(response: ApiResponse) -> Result<Self, Error>;
}
impl<R> FromApi for R
where
R: DeserializeOwned,
{
default fn convert(response: ApiResponse) -> Result<R, Error> {
eprintln!("deserializing the response");
serde_json::from_str(response).map_err(Into::into)
}
}
impl FromApi for () {
fn convert(_response: ApiResponse) -> Result<Self, Error> {
eprintln!("Ignoring the response");
Ok(())
}
}
fn send<R: FromApi>() -> Result<R> {
eprintln!(r#""sending" the request"#);
let api_response = "";
R::convert(api_response)
}
fn main() {
let _r: () = send().expect("Unable to deserialize");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.