具有类型限制的 Rust 特征

Rust Traits with Type Bounds

我想使用 Rust 特性编写数据库的基本抽象。

pub trait Keyable {
    type Key;
    fn key(&self) -> &Self::Key;
}

// type alias for result - DbError are defined elsewhere
pub type Result<T> = Result<T, DbError>;

pub trait Database {
    type Item;

    fn get(&self, id: Keyable) -> Result<Self::Item>;    
    fn upsert(&self, item: Self::Item) -> Result<Keyable>;
}

我很难表达这一点:Database::Item 必须至少是 Keyable。

有两个用例:

  1. 我可以使用一些任意类型,它知道如何在我的 Database::get(k: Keyable) 函数中 return 一个 key() 而 return 一些项目(这很可能不仅仅是 key().
  2. 在我的 fn Database::upsert() 函数中,我希望能够使用该项目至少是 Keyable 的事实,因此访问 key() 来查找数据库以做出决定,如果我只需插入或更新。

您可以在关联类型上放置特征绑定:

pub trait Database {
    type Item: Keyable;

然后,您可以在函数签名中使用该特征的关联类型:

    fn get(&self, id: &<Self::Item as Keyable>::Key) -> Result<Self::Item>;    
    fn upsert(&self, item: Self::Item) -> Result<<Self::Item as Keyable>::Key>;

(我还添加了一个 & 因为 get() 可能不需要使用密钥数据。)

将所有内容组合成一个可编译的示例:

pub enum DbError { Something }
pub type Result<T> = std::result::Result<T, DbError>;

pub trait Keyable {
    type Key;
    fn key(&self) -> &Self::Key;
}

pub trait Database {
    type Item: Keyable;

    fn get(&self, id: &<Self::Item as Keyable>::Key) -> Result<Self::Item>;    
    fn upsert(&self, item: Self::Item) -> Result<<Self::Item as Keyable>::Key>;
}