很长一段时间以来,我的目标都是实现这样的 API:
struct GetEvent;
fn handler(_event: &mut GetEvent) {}
pub fn main() {
let mut server = Server::default();
server.handle(handler);
server.emit(PostEvent);
}
名称和类型只是示例,这个实际程序与 HTTP 无关
这两天,我又回到了这个问题。有几次我感觉如此接近,但我就是不太明白。我真的是拔头发了
下面你会发现我尝试过的事情,如果你立即知道该怎么做并且比我更聪明,你可以跳过所有这些:D
首先,基本结构可以在这里获得。这个可以编译,因此相关方法已被
todo!()
打断。
所以,我们开始吧:
天真地,我只是查找如何使用any,并创建了这个哈希映射:
struct Server {
handlers: HashMap<TypeId, Box<dyn Handler<dyn Any>>>,
}
fn handle<E>(&mut self, handler: impl Handler<E>) {
self.handlers.insert(TypeId::of::<E>(), Box::new(handler));
}
但是:
--> src/main.rs:26:49
|
26 | self.handlers.insert(TypeId::of::<E>(), Box::new(handler));
| ^^^^^^^^^^^^^^^^^ the trait `for<'a> Fn(&'a mut (dyn Any + 'static))` is not implemented for `impl Handler<E>`, which is required by `impl Handler<E>: Handler<(dyn Any + 'static)>`
|
老实说我不知道这意味着什么。但我假设,这行不通。
struct Server {
handlers: HashMap<TypeId, Box<dyn Any>>,
}
fn handle<E: 'static>(&mut self, handler: impl Handler<E>) {
self.handlers.insert(TypeId::of::<E>(), Box::new(handler));
}
这...可以编译!胜利!遗憾的是没有。在阅读了一个小时有关向下转换的内容后,我遇到了运行时错误!
fn emit<E: 'static>(&mut self, mut event: E) {
let Some(handler) = self.handlers.get_mut(&TypeId::of::<E>()) else {
println!("did not find handler...");
return;
};
let handler = handler.downcast_ref::<Box<dyn Handler<E>>>().unwrap();
handler.handle(&mut (event as E));
}
thread 'main' panicked at src/main.rs:36:69:
called `Option::unwrap()` on a `None` value
但我想我明白为什么这不起作用。注册函数
fn handle<E: 'static>(...)
将转为静态调度,因此类型不会是Box<dyn Handler<E>>
,而是:alloc::boxed::Box<rust_test::handler>
。这是我的处理程序的静态函数指针。
Handler
特质吗?fn handle<E: 'static>(&mut self, handler: impl Handler<E>) {
let handler = Box::new(handler) as Box<dyn Handler<E>>;
self.handlers.insert(TypeId::of::<E>(), handler);
}
不!因为...呃,不!
= note: expected struct `Box<(dyn Any + 'static)>`
found struct `Box<dyn Handler<E>>`
啊哈!需要
Any + 'static
作为处理程序的基本特征?显然不是:
cannot cast `dyn Handler<E>` to `dyn Any`, trait upcasting coercion is experimental
*人工智能没有直接生成任何代码或任何其他内容。一切都已经转变并经过我的审查。
“不可能...某种类型的擦除...bla bla”。
好的,当然:
trait HandlerErased {
fn handle(&self, event: &mut dyn Any);
}
impl<E, H: Handler<E>> HandlerErased for H {
fn handle(&self, event: &mut dyn Any) {
// Check if correct type
todo!();
}
}
虽然我不太喜欢这段代码,但在此处检查类型是否正确似乎有点错误。此时,无论如何它应该是正确的处理程序类型。但我已经绝望了,所以发送吧!
一如既往......不起作用,只会在面对时产生更多幻觉:
error[E0207]: the type parameter `E` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:24:6
|
24 | impl<E, H: Handler<E>> HandlerErased for H {
| ^ unconstrained type parameter
我尝试了一些其他的事情,但我认为其中没有一个值得注意。是的,我知道我可以使用一个巨大的 Enum,但这就是我现在正在做的事情,而且 API 相当混乱。这样做的目标是,API 的用户可以选择他们想要处理的事件。
此外,这可能允许我检测(无需成为宏向导2)并根据它生成一些值(服务器功能,如果您感兴趣的话)。
我已阅读这些资源以及更多内容:
Fn
,并且我希望它是基于特征的。我也无法理解这个Option
生意是做什么的。PS:
- 这是关于什么的...
-我恳请编辑战士不要删除上下文,和/或消除这个问题。谢谢!
这可以完成,但需要一些装箱层 - 您需要一层来统一不同的
Handler<E>
实现 (Box<dyn Handler<E>>
),并且需要另一层来统一这些框以擦除 E
后面的 Any
类型( Box<dyn Any>
)。
首先,服务器定义如下:
#[derive(Default)]
struct Server {
handlers: HashMap<TypeId, Box<dyn Any>>,
}
添加处理程序需要对其进行装箱。我们会让来电者处理这个问题。
fn handle<E: 'static>(&mut self, handler: Box<dyn Handler<E>>) {
let boxed: Box<dyn Any> = Box::new(handler);
self.handlers.insert(TypeId::of::<E>(), boxed);
}
请注意,我们必须绑定
E: 'static
,因为 TypeId
不会对生命周期进行编码,因为生命周期的可能数量在技术上是无限的。
要使用它,我们必须将
Any
向下转换回 Box<dyn Handler<E>>
。 这里我只是 unwrap()
结果,因为错误是意外的并且表明操作 handlers
映射的函数中存在错误,因此恐慌是适当的。
fn emit<E: 'static>(&mut self, mut event: E) {
if let Some(boxed) = self.handlers.get(&TypeId::of::<E>()) {
boxed
.downcast_ref::<Box<dyn Handler<E>>>()
.unwrap()
.handle(&mut event);
}
}
注意,我们可以使用一些
unsafe
技巧来避免双重装箱,但只有当性能实际上是这种方法的问题时,我才会使用这些技巧。