簡體   English   中英

如果沒有要返回的內容,如何從泛型函數返回有意義的東西?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM