sondrele
sondrele

Reputation: 21

Unresolved name for Trait when specifying the Type (<Type as Trait>)

I have a struct Bar that implements the Foo trait.

struct Bar;

trait Foo {
    fn foo(&self) {
        print!("Foo");
    }
}

impl Foo for Bar {}

I also have Print trait that takes a Kind parameter. Both Foo and Bar implement Print with Bar as its Kind.

trait Print {
    type Kind;
    fn print(_: &Self::Kind);
}

impl Print for Bar {
    type Kind = Bar;
    fn print(_: &Bar) {
        println!("Bar");
    }
}

impl Print for Foo {
    type Kind = Bar;
    fn print(bar: &Bar) {
        bar.foo();
        Bar::print(bar);
    }
}

Finally, I want to print Bar using the different implementations.

fn main() {
    let b = Bar;
    Bar::print(&b);          // prints: Bar
    Foo::print(&b);          // prints: FooBar
    <Bar as Foo>::print(&b); // error
}

The code is also available in the playground

The two first calls to print works fine but the line <Bar as Foo>::print(&b); gives the following compilation error:

error[E0576]: cannot find method or associated constant `print` in trait `Foo`
  --> src/main.rs:35:19
   |
35 |     <Bar as Foo>::print(&b); // error
   |                   ^^^^^ not found in `Foo`

I would have expected the last two lines to print the same thing. Why do I get an error saying that Foo::print is an unresolved name, when the line above works fine? What's the difference between the two lines?

Upvotes: 1

Views: 290

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90852

<A as B> is Fully Qualified Syntax (FQS) meaning “find the implementation of the trait B for the type A”. Your <Bar as Foo>::print, then, is trying to call the print method from the Foo trait with Bar as Self. The Foo trait does not have any such method, and so it quite naturally fails. What you need there for that to work is <Foo as Print>::print.

Bar::print looks first for an intrinsic method on the type Bar and then for any method named print on any trait that Bar implements, and so is resolved as <Bar as Print>::print. The deal is the same for Foo::Print.

Upvotes: 2

Related Questions