【发布时间】:2016-02-26 16:01:36
【问题描述】:
我有这个结构:
#[deriving(Clone)]
pub struct MiddlewareStack {
handlers: Vec<Box<Middleware + Send>>
}
然后我有代码将处理程序添加到handlers
pub fn utilize<T: Middleware>(&mut self, handler: T){
self.middleware_stack.add(handler);
}
这很好,但我想知道,为什么必须使用泛型?
所以我尝试了这个:
pub fn utilize(&mut self, handler: Middleware){
self.middleware_stack.add(handler);
}
但这给我留下了这个错误:
error: reference to trait `Middleware` where a type is expected; try `Box<Middleware>` or `&Middleware`
pub fn utilize(&mut self, handler: Middleware){
好的,那么。特征不能直接用作参数(因为它们会被删除?)。但是为什么它们作为泛型类型参数是合法的呢?
所以,我继续尝试:
pub fn utilize(&mut self, handler: Box<Middleware + Send>){
self.middleware_stack.add(handler);
}
但这给我留下了以下错误:
error: failed to find an implementation of trait middleware::Middleware for Box<middleware::Middleware:Send>
self.middleware_stack.add(handler);
所以,我想知道:该代码真的必须使用泛型吗?不,我不希望它不使用泛型是有特殊原因的。我更想了解为什么它必须使用泛型,因为它来自诸如 Java 的 C# 之类的语言,它可能只是一个使用接口作为参数的非泛型方法,应该粗略地转换为 Rust 中的特征。
对弗拉基米尔出色回答的跟进
你试图在这个函数中传递一个特征对象。但是 trait 对象并没有实现相应的 trait,也就是说,它们的类型不满足各自的 trait bound,除非这些 trait 明确地实现在它们身上
我认为,这对我来说很奇怪。鉴于add 看起来像这样,我希望能够使用盒装的Middleware 呼叫self.middleware_stack.add(handler):
pub fn add<T: Middleware> (&mut self, handler: T) {
self.handlers.push(box handler);
}
但是好的,:Middleware 绑定对Box<Middleware> 不满意,再想一想这实际上是有道理的。否则无论如何我都会在上面的代码中使用双重装箱。
如果我将使用更改为:
pub fn utilize(&mut self, handler: Box<Middleware + Send>){
self.middleware_stack.add(handler);
}
和add 到
pub fn add (&mut self, handler: Box<Middleware+Send>) {
self.handlers.push(handler);
}
它按预期工作。请注意,它们不在同一个模块中,因此是封装。但这意味着在调用者站点上我必须将代码更改为utilize(box some_middleware)。
通过通用实现,我可以在层的最底部调用box
pub fn add<T: Middleware> (&mut self, handler: T) {
self.handlers.push(box handler);
}
但是对于非泛型实现,我必须在调用者网站上装箱,否则我会遇到:
error: reference to trait `Middleware` where a type is expected; try `Box<Middleware>` or `&Middleware`
让我们面对现实吧:我永远不能将Middleware 作为一个简单的参数。我总是需要Box<Middleware> 或&Middleware,这意味着我必须在此过程中及早进行拳击,而使用泛型我可以在路上进行拳击。
我想我还没有完全理解为什么会这样。因为如果编译器翻译了
pub fn add<T: Middleware> (&mut self, handler: T) {
self.handlers.push(box handler);
}
进入:
pub fn add (&mut self, handler: Middleware) {
self.handlers.push(box handler);
}
反正在某个时候。
为什么我不允许使用未装箱版本的Middleware 作为简单参数,如果编译器在幕后或多或少会这样做?
【问题讨论】: