0

我正在 Rust 中构建一个库,该库具有一种send使用 reqwest 对本地 RPC 服务器执行 HTTP 请求的方法。

R此方法在Resultwhere中返回泛型类型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.

R我试图通过用包装来解决这个问题Option,但这意味着我必须对每个响应进行双重解包,并且来自 reqwest 的 98% 的响应确实在其响应中包含数据,所以感觉有点矫枉过正。

我也尝试返回一个自制的EmptyResponse类型,但编译器抱怨:expected type R, found type EmptyResponse. 我认为返回一个类型EmptyResponse将是我想要的,但也许有人可以就如何更好地做到这一点提供一些提示。

4

2 回答 2

1

务实的答案是有两个功能:

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");
}
于 2019-02-07T15:30:55.840 回答
1

您可以返回文档Result<Option<R>, ApiError>中所示的an ,然后像这样匹配它:

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
}

R我试图通过用包装来解决这个问题Option,但这意味着我必须对每个响应进行双重解包,并且来自 reqwest 的 98% 的响应确实在其响应中包含数据,所以感觉有点矫枉过正。

打开包装Option是一个非常便宜的操作,没有什么可担心的。

于 2019-02-07T04:41:38.993 回答