I want to write a basic abstraction of a database, using Rust traits.
pub trait Keyable {
type Key;
fn key(&self) -> &Self::Key;
}
and
// 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>;
}
I am struggling to express this: Database::Item must be at least Keyable.
There are two use cases:
You can place a trait bound on an associated type:
pub trait Database {
type Item: Keyable;
Then, you can use that trait's associated type(s) in function signatures:
fn get(&self, id: &<Self::Item as Keyable>::Key) -> Result<Self::Item>;
fn upsert(&self, item: Self::Item) -> Result<<Self::Item as Keyable>::Key>;
(I also added an &
because get()
probably shouldn't be required to consume the key data.)
Putting that all together to a compilable example:
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>;
}