将泛型方法转换为特征对象安全方法
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>)>),
) { }
一个简单的方法是要求输入迭代器 return 引用。这编译:
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>)>),
) { }
请注意,拥有迭代器适配器是一种很好的方式 return 可以进一步操作的迭代器:
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
特征的通用结构。)
现在:如果您不想要求输入迭代器 return 引用,则无法 return 您的新迭代器。
您在示例代码中所做的是在迭代器中创建一个小缓冲区,并return引用它。
如果该缓冲区存储在您的迭代器结构中,您尝试创建的称为 流式迭代器,目前无法实现。 This extremely long blog post 解释原因;本质上,它需要对 Rust 的类型系统进行大而复杂的扩展。
你可以做这样的事情,如果你重新安排你的代码让用户将闭包传递到你的函数中。然后,您可以控制何时调用闭包,这样您就可以将 returned 值存储到缓冲区中,并将对缓冲区的引用传递到闭包中。但这不像通常的 Iterator
界面那样符合人体工程学。
这就是您对示例代码所做的事情...我不确定为什么它不起作用。如果您将 take_dyn
更改为单个 &'b (dyn 'b + Deref<Target = u8>)>
并重复调用它,它应该可以工作。
我想制作一个适配器来删除通用参数(以生成特征对象),如下例所示。
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>)>),
) { }
一个简单的方法是要求输入迭代器 return 引用。这编译:
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>)>),
) { }
请注意,拥有迭代器适配器是一种很好的方式 return 可以进一步操作的迭代器:
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
特征的通用结构。)
现在:如果您不想要求输入迭代器 return 引用,则无法 return 您的新迭代器。
您在示例代码中所做的是在迭代器中创建一个小缓冲区,并return引用它。
如果该缓冲区存储在您的迭代器结构中,您尝试创建的称为 流式迭代器,目前无法实现。 This extremely long blog post 解释原因;本质上,它需要对 Rust 的类型系统进行大而复杂的扩展。
你可以做这样的事情,如果你重新安排你的代码让用户将闭包传递到你的函数中。然后,您可以控制何时调用闭包,这样您就可以将 returned 值存储到缓冲区中,并将对缓冲区的引用传递到闭包中。但这不像通常的 Iterator
界面那样符合人体工程学。
这就是您对示例代码所做的事情...我不确定为什么它不起作用。如果您将 take_dyn
更改为单个 &'b (dyn 'b + Deref<Target = u8>)>
并重复调用它,它应该可以工作。