在Rust中,如何在具有关联类型的特征上进行抽象?

时间:2016-12-06 19:50:15

标签: rust size abstract traits

我为不同的主机/提供商编写了一个下载器,需要抽象出他们为文件提供的不同元信息。例如,一个主机可能返回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向我提供了一个工作的解决方案,但却不是我希望/想要的。一般解决方案是thisTranslated 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>>>,可以通过指定我自己的类型来解决(就像我一样)。

其他令人恼火的事情:

  1. 我必须为每个新的Wrapper方法复制所有Remote方法。
  2. 最令人恼火的是:正如您在我的应用示例中所看到的,我必须在包装器中编写类似self.0.foo(bar)?.into_iter().map(|x| Box::new(x) as Box<Remote>).collect()的内容,以便将Remote内的所有Vec转换为{ {1}}秒。虽然打字很令人沮丧,但表现也很糟糕。
  3. Box<Remote>特征相同。我必须Remote并导入impl Remote for Box<Remote>特征并手动将所有特征方法委托给Box的内部......
  4. 还有其他办法吗?

0 个答案:

没有答案