I'm trying to implement something on Rust with traits and associated types. I'm not sure how to form my question with words, so I'll add a code snippet which will hopefully illustrate what I'm trying to do.
pub trait Person {}
pub trait Directory<P: Person> {
type Per = P;
fn get_person(&self) -> Self::Per;
}
pub trait Catalog {
type Per : Person;
type Dir : Directory<Self::Per>;
fn get_directory(&self) -> Self::Dir;
}
fn do_something<C>(catalog: C) where C: Catalog {
let directory : C::Dir = catalog.get_directory();
// let person : C::Per = directory.get_person();
// The code above fails with:
// error: mismatched types:
// expected `<C as Catalog>::Per`,
// found `<<C as Catalog>::Dir as Directory<<C as Catalog>::Per>>::Per`
// (expected trait `Catalog`,
// found trait `Directory`) [E0308]
let person = directory.get_person();
do_something_with_person(person);
}
fn do_something_with_person<P: Person>(p: P) {}
I would expect that the above code would compile, but it does not.
Instead, I get:
error: the trait `Person` is not implemented for the type `<<C as Catalog>::Dir as Directory<<C as Catalog>::Per>>::Per` [E0277]
Which, AFAICT, means that the compiler cannot determine that the person variable has the Person trait.
I'm using the following rustc version:
rustc 1.2.0-dev (a19ed8ad1 2015-06-18)
Am I missing something?
Here there's the correction:
pub trait Directory<P: Person> {
type Per : Person = P;
fn get_person(&self) -> Self::Per;
}
The type Per
in Directory
can be redefined in trait implementations. The compiler doesn't know if Self::Per
(which is the re-defined Per
in the implementation) implements the trait Person
, so you have to bound it to implement Person
.
Here’s the correct code:
pub trait Person {}
pub trait Directory {
type Person: Person;
fn get_person(&self) -> Self::Person;
}
pub trait Catalog {
type Dir: Directory;
fn get_directory(&self) -> Self::Dir;
}
fn do_something<C: Catalog>(catalog: C) {
let directory = catalog.get_directory();
let person = directory.get_person();
do_something_with_person(person);
}
fn do_something_with_person<P: Person>(p: P) {}
<P: Person>
is generics syntax. Associated type definitions do not use generic syntax.
Go for the full name in general; don’t abbreviate it Per
, leave it Person
. It’s always qualified (Directory::Person
, C::Person
, &c.), so there’s no ambiguity. (Dir
is an acknowledged short form of Directory
, so there I guess either would be acceptable. I’d probably tend to go with Directory
, however.)
There’s no need to have the associated type Person
specified on Catalog
, either; Self::Dir::Person
will do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With