我为不同的主机/提供商编写了一个下载器,需要抽象出他们为文件提供的不同元信息。例如,一个主机可能返回MD5总和,另一个主机可能返回SHA1总和甚至根本没有校验和。我写了一个Hoster
特征,可以返回一个文件(其特定类型应该是未知的)。
trait Hoster {
type File: Remote;
fn meta(&self, urls: &Vec<Url>) -> hyper::Result<Vec<Self::File>>;
// several other methods
}
meta
函数接收URL并返回特定类型的元信息。反过来,这种类型可能有自己的功能。
在我的代码中的任何地方使用Hoster
时,编译器会抱怨我需要提供特定的File
特征类型。我在IRC问过,kimundi向我提供了一个工作的解决方案,但却不是我希望/想要的。一般解决方案是this。 Translated to my example:
pub trait Remote: std::fmt::Debug {
fn url(&self) -> String;
}
trait _Hoster {
type File: Remote + 'static;
fn id(&self) -> &'static str;
// Returns true if this host is responsible for this URL, false otherwise.
fn accepts(&self, url: &url::Url) -> bool;
// Returns meta information on given URLs.
fn meta(&self, url: &Vec<url::Url>) -> hyper::Result<Vec<Self::File>>;
}
struct Wrapper<T>(T);
use std::ops::Deref;
impl Remote for Box<Remote> {
fn url(&self) -> String {
self.deref().url()
}
}
impl<T: _Hoster> _Hoster for Wrapper<T> {
type File = Box<Remote>;
fn id(&self) -> &'static str {
self.0.id()
}
fn accepts(&self, url: &url::Url) -> bool {
self.0.accepts(url)
}
fn meta(&self, urls: &Vec<url::Url>) -> hyper::Result<Vec<Box<Remote>>> {
self.0.meta(urls)?.into_iter().map(|x| Box::new(x) as Box<Remote>).collect()
}
}
pub type Hoster = _Hoster<File = Box<Remote>>;
但正如您所看到的,我必须在代码中指定Box<Trait<Out=Box<Assoc>>>
,可以通过指定我自己的类型来解决(就像我一样)。
其他令人恼火的事情:
Wrapper
方法复制所有Remote
方法。 self.0.foo(bar)?.into_iter().map(|x| Box::new(x) as Box<Remote>).collect()
的内容,以便将Remote
内的所有Vec
转换为{ {1}}秒。虽然打字很令人沮丧,但表现也很糟糕。Box<Remote>
特征相同。我必须Remote
并导入impl Remote for Box<Remote>
特征并手动将所有特征方法委托给Box的内部...... 还有其他办法吗?