![](/img/trans.png)
[英]Why does a generic method inside a trait require trait object to be sized?
[英]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.