generics - 将未调整大小和基于动态调度的特征作为参数传递的问题
问题描述
我正在尝试编写一个Query
相互馈送的传感器网络(下面称为)。
AQuery<A, B>
接受类型 的输入项A
,并输出 中的值B
。它通过将它们提供给一个接收器来实现,该接收器Sink<B>
公开适当的方法来消耗元素。
pub trait Sink<A> {
fn init(&mut self);
fn next(&mut self, item: A);
fn end(&mut self);
}
pub trait Query<A,B>: {
fn init(&mut self, sink: &mut dyn Sink<B>);
fn next(&mut self, item: A, sink: &mut dyn Sink<B>);
fn end(&mut self, sink: &mut dyn Sink<B>);
}
现在,给定 aQuery<A, B>
和 a Query<B, C>
,可以将它们组合成 a Query<A, C>
。我将调用此操作Pipeline
。Pipeline
下面,为了方便起见,我定义了一个构造函数。
pub struct Pipeline<'a, A, B, C, QAB: Query<A, B>, QBC: Query<B, C> > {
q_ab: &'a mut QAB,
q_bc: &'a mut QBC,
_abc : PhantomData<(A, B, C)>
}
impl<'a, A, B, C, QAB: Query<A, B>, QBC: Query<B, C>> Pipeline<'a, A, B, C, QAB, QBC>{
pub fn new(q1: &'a mut QAB, q2: &'a mut QBC) -> Self{
Self {q_ab : q1, q_bc: q2, _abc:PhantomData}
}
}
为了实现管道,我们需要一个中间接收器,它的唯一工作是将输出推Query<A, B>
送到Query<B, C>
struct PushSink<'a, B, C, QBC : Query<B, C>, S : Sink<C> + ?Sized> {
q_bc : &'a mut QBC,
s_c : &'a mut S,
_bc : PhantomData<(B, C)>
}
impl <'a, B, C, QBC: Query<B, C>, S: Sink<C> + ?Sized> PushSink<'a, B, C, QBC, S>{
pub fn new(q_bc: &'a mut QBC, s_c : &'a mut S) -> Self{
PushSink {q_bc : q_bc, s_c : s_c, _bc : PhantomData}
}
}
impl<'a, B, C, QBC: Query<B, C>, S: Sink<C> + ?Sized> Sink<B> for PushSink<'a, B, C, QBC, S>{
fn init(&mut self) {
self.q_bc.init(self.s_c);
}
fn next(&mut self, item: B) {
self.q_bc.next(item, self.s_c);
}
fn end(&mut self) {
self.q_bc.end(self.s_c);
}
}
最后,我们可以使用这个定义来定义如何Pipeline
作为Query<A, C>
impl<'a, A, B, C, QAB: Query<A, B>, QBC: Query<B, C>> Query<A, C> for Pipeline<'a, A, B, C, QAB, QBC>{
fn init(&mut self, sink: &mut dyn Sink<C>){
self.q_ab.init(&mut PushSink::new(self.q_bc, sink))
}
fn next(&mut self, item: A, sink: &mut dyn Sink<C>){
self.q_ab.next(item, &mut PushSink::new(self.q_bc, sink))
}
fn end(&mut self, sink: &mut dyn Sink<C>){
self.q_ab.end(&mut PushSink::new(self.q_bc, sink))
}
}
但是,这不起作用,因为
error[E0277]: the size for values of type `S` cannot be known at compilation time
--> test.rs:47:23
|
39 | impl<'a, B, C, QBC: Query<B, C>, S: Sink<C> + ?Sized> Sink<B> for PushSink<'a, B, C, QBC, S>{
| - this type parameter needs to be `std::marker::Sized`
...
47 | self.q_bc.end(self.s_c);
| ^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `S`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required for the cast to the object type `dyn Sink<C>`
我该如何解决这种情况?
我知道如何在使用接口而不是特征的 Java 中实现相同的想法。它似乎在 Java 中没有问题。
另外,我想要一个基于特征的解决方案。我希望将Query<A, B>
andSink<B>
等作为特征而不是其他东西(例如,枚举数据类型)。
如果可能的话,我也想避免使用盒子。我更喜欢使用泛型和特征而不是框的解决方案。
我也尝试过将签名更改Query<,>
为
pub trait Query<A,B>: {
fn init(&mut self, sink: &mut (dyn Sink<B> + ?Sized));
fn next(&mut self, item: A, sink: &mut (dyn Sink<B> + ?Sized));
fn end(&mut self, sink: &mut dyn Sink<B>);
}
但显然,这是不允许的
编辑:游乐场链接,感谢@eggyal
解决方案
推荐阅读
- android - Google Glass Enterprise Edition 2 RecognitionService startListening 出现意外错误
- kotlin - 无法在 kotlin 多平台模块中解析 io.kotest:kotest-runner-junit5-jvm:4.1.1
- r - 多个类似的 csv 文件中的相同功能并在单个 csv 文件中输出?
- firebase - 保存规则时出错 - NaN 行:规则集使用旧版本(版本 [1])。请更新到最新版本(版本 [2])
- c# - 如何在 C# 中用负号和正号为 40 位数字编码格式字符串?
- c++ - 即使功能有效,测试仍然失败
- javascript - React 将数组映射到下拉问题
- c# - OracleCommandBuilder.DeriveParameters() 抛出 OracleException:ORA-06564:对象不存在 ORA-06512:在“SYS.DBMS_UTILITY”
- javascript - 在mongodb中访问nodejs中的对象属性时未定义
- r - 无法通过 for 循环附加向量