In the following program (play), the FooBar trait provides the bar method, but the actual type of the object returned by bar seems to be hidden. If I use a type argument instead of an associated type, it works (play).
Why are associated types treated differently? Or am I doing it wrong?
use std::ops::DerefMut;
pub trait FooBar: Sized {
type Assoc: Sized + DerefMut<Target=Self>;
fn foo(&mut self) -> Option<Self::Assoc>;
fn bar(mut this: Self::Assoc) -> Result<Self::Assoc, Self::Assoc> {
unimplemented!()
}
}
#[derive(Debug)]
struct Test(u32);
impl FooBar for Test {
type Assoc = Box<Test>;
fn foo(&mut self) -> Option<Self::Assoc> {
unimplemented!()
}
}
fn main() {
let mut tt = Test(20);
let tt_foo: Box<Test> = tt.foo().unwrap(); // this is ok
let tt_bar: Box<Test> = FooBar::bar(Box::new(tt)).unwrap(); // but not this
assert_eq!(tt_bar.0, 20);
}
If your method is
fn bar(mut this: Self::Assoc) -> Result<Self::Assoc, Self::Assoc>
and you try to call it with
FooBar::bar(Box::new(tt))
how is Rust supposed to know what type Self is? Box::new(tt) is Self::Assoc right, but you can’t get Self from that, several types could have the same Assoc.
And that’s what rustc is complaining about:
type annotations required
You’d have to annotate what type Self is:
let tt_bar: Box<Test> = <Test as FooBar>::bar(Box::new(tt)).unwrap();
or equivalently:
let tt_bar: Box<Test> = Test::bar(Box::new(tt)).unwrap();
The problem is you are trying to access the associated type from the trait. You can only access it from a type that implements the trait, such as from Test:
let tt_bar: Box<Test> = Test::bar(Box::new(tt)).unwrap();
FooBar::Assoc is not a concrete type, so you cannot use it. When you implemented FooBar for Test, you gave Test::Assoc a concrete type, which is accessible:
type Assoc = Box<Test>;
In the code with the generic type, a new copy of FooBar::bar was created with a concrete type. Because you requested a Box<Test>, the new function's signature would be this:
fn bar(mut this: Box<Test>) -> Result<Box<Test>, Box<Test>>
Box<Test> is a concrete type, so it works.
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