簡體   English   中英

Rust:特性中的通用返回類型,用於返回非對象安全特性的實現

[英]Rust: Generic return types in Traits for implementations that return non object-safe Traits

我是 Rust 的新手,我想通過實施一些小項目來學習這門語言並更好地理解。 我的第一次嘗試是解析從 MQTT 代理收到的 JSON 數據。 我很高興在tornadoserde的幫助下很容易做到這一點。 然而,很快出現了一種我想(理想情況下)提取到特征中的模式。

let person_stream = sender.subscribe().filter_map(|data| {
    if let Ok(value) = data {
        return serde_json::from_slice::<Person>(&value).ok();
    }
    None
});

其中sender通常是tokio::sync::*::Sender並且Person將實現serde::de::DeserializeOwned Trait。

因此,我們的目標是實現采用tokio::stream::StreamExt<Item = Vec<u8>>並將其transform為另一個StreamExt的東西,其中關聯類型Item將實現DeserializOwned

我花了很長時間才弄清楚(因為我最初想使用帶有泛型的 Trait 或 function),我想出了

fn transform<T, U, V>(stream: U) -> impl StreamExt<Item = T>
where
    T: serde::de::DeserializeOwned,
    U: StreamExt<Item = Result<Vec<u8>, V>>,
{
    stream.filter_map(|data| {
        if let Ok(value) = data {
            return serde_json::from_slice::<T>(&value).ok();
        }
        None
    })
}

雖然這行得通,但我最初想要一個像

trait Transform<T>
{
    fn transform(self) -> T;
}

或實現Into實際上是相同的,我可以為StreamExt<Item = Vec<u8>>實現。 由於impl Trait return 不適用於 Traits,這是我認為的唯一選擇。 但是,我在實現這一點時遇到了幾個問題。

  1. 使用tokio::stream::filter_map::FilterMap<_,_> for T (這是filter_map()的返回類型)是不可能的,因為模塊filter_mapprivate
  2. 使用Box<dyn StreamExt>也是不可能的,因為StreamExt在幾個函數中返回Self 不過,我一開始就不想要堆開銷;)

所以我的問題是:考慮到filter_map()的返回類型是private的並且StreamExt不是對象安全的,我可以在這里做些什么來獲得 Trait 實現的語法糖嗎? 使用會很酷

let person_stream = receiver.transform();

into() 顯然我有一個可行的實現,所以這對我來說並不是一個真正的關鍵問題。 但正如我一開始所說,我想首先對 Rust 有更深入和更好的了解。

我注意到有tokio-serde crate,但乍一看它只處理框架數據,所以我沒有深入研究它。

PS:當類型推斷失敗時,我實施的免費 function transform也遇到了問題。 例如,當將新的 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 交給 function 時

async fn debug_sink<T>(mut receiver: T)
where
    T: StreamExt + Unpin,
    T::Item: std::fmt::Debug,
{
    while let Some(item) = receiver.next().await {
        println!("Item: {:#?}", item);
    }
}

在這種情況下,與像這樣的匯相比,它顯然無法推斷T in transfer

async fn person_sink(mut receiver: impl StreamExt<Item = Person> + Unpin) {
    while let Some(person) = receiver.next().await {
        println!("Person: {:#?}", person);
    }
}

但是我不想注釋所有類型參數,只注釋它無法推斷的一個。 經過反復試驗,我發現我可以使用

transform::<Person, _, _>(stream);

我完全不知道。 不過,我在文檔中找不到這個。 這是一些隱藏的功能,還是我只是未能正確 rtfm? :)

我認為你需要的東西可以在每晚的type_alias_impl_trait功能下獲得。 基本上,它允許您在 trait 中編寫關聯類型,然后在實現中,使用impl BaseTrait語法而不是編寫命名類型。

我懶得用type_alias_impl_trait編寫您的代碼(並且您沒有提供可編譯的代碼段),但這是一個工作示例( playground ):

#![feature(type_alias_impl_trait)]

use std::fmt::Debug;

trait Foo {
    type Output: Debug;

    fn do_something() -> Self::Output;
}

impl Foo for () {
    type Output = impl Debug;

    fn do_something() -> Self::Output {
        "hello!"
    }
}

請注意()::do_something實際上如何返回&'static str但從未提及此類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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