簡體   English   中英

將泛型方法轉換為 trait object 安全方法

[英]Turn generic method into trait object safe method

我想制作一個刪除通用參數(以生成特征對象)的適配器,如下例所示。

use std::ops::Deref;

fn make_dyn_box<I, S>(iter_in: I)
where
    I: Iterator<Item = S>,
    S: Deref<Target = u8>,
{
    let mut iter_out = iter_in.map(
        |s| -> Box<dyn Deref<Target = u8>> {Box::new(s)}
    );
    take_dyn_box(&mut iter_out)
}

fn take_dyn_box<'a: 'b, 'b>(
    iter: &'a mut (dyn 'a + Iterator<Item = Box<dyn 'b + Deref<Target = u8>>>),
) { }

有沒有辦法在沒有堆分配、只使用安全代碼且沒有外部依賴項的情況下完成此任務?

以下是我想要的想法,但借用檢查器不允許這樣做。

use std::ops::Deref;

fn make_dyn<I, S>(iter_in: I)
where
    I: Iterator<Item = S>,
    S: Deref<Target = u8>,
{
    let mut item = None;
    let item = &mut item;
    let mut iter_out = iter_in.map(|s| -> &dyn Deref<Target = u8> {
        item.replace(s);
        Option::as_ref(item).unwrap()
    });
    take_dyn(&mut iter_out)
}

fn take_dyn<'a: 'b, 'b>(
    iter: &'a mut (dyn 'a + Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>),
) { }

一種簡單的方法是要求輸入迭代器返回引用。 這編譯:

fn make_dyn<'b, I, S>(iter_in: I)
where
    I: Iterator<Item = &'b S>,
    S: Deref<Target = u8> + 'b,
{
    let mut iter_out = iter_in.map(|s| -> &dyn Deref<Target = u8> {
        s as _
    });
    
    take_dyn(&mut iter_out)
}

fn take_dyn<'a: 'b, 'b>(
    _iter: &'a mut (dyn 'a + Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>),
) { }

請注意,讓迭代器適配器返回可以進一步操作的迭代器是一種很好的方式:

fn make_dyn_<'b, I, S>(iter_in: I) -> impl Iterator<Item = &'b (dyn 'b + Deref<Target = u8>)>
where
    I: Iterator<Item = &'b S>,
    S: Deref<Target = u8> + 'b,
{
    iter_in.map(|s| -> &dyn Deref<Target = u8> {
        s as _
    })
}

(您也可以將其定義為實現Iterator特征的通用結構。)

現在:如果您不想要求輸入迭代器返回引用,那么就沒有辦法返回您的新迭代器。

您在示例代碼中所做的是在迭代器中創建一個小緩沖區,並返回對它的引用。

如果該緩沖區存儲在您的迭代器結構中,則您嘗試創建的內容稱為流式迭代器,目前無法實現。 這篇極長的博文解釋了原因; 本質上,它需要對 Rust 的類型系統進行大量而繁瑣的擴展。

如果您重新排列代碼以讓用戶將閉包傳遞給您的函數,您可以這樣做。 然后,您可以控制何時調用閉包,這樣您就可以將返回的值存儲到緩沖區中,並將對緩沖區的引用傳遞給閉包。 但這不像通常的Iterator界面那樣符合人體工程學。

這就是您對示例代碼所做的事情......我不確定為什么它不起作用。 如果您將take_dyn更改為采用單個&'b (dyn 'b + Deref<Target = u8>)>並反復調用它,它應該可以工作。

暫無
暫無

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

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