Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"expected type parameter, found struct"

Tags:

rust

I've been messing around with traits using Rust and I've come across a problem. Here's some code:

struct Foo;

trait Bar {}

impl Bar for Foo {}

fn bar<B: Bar>(bar: B) {}

fn barr<B: Bar>() {
    bar(Foo); // 1. THIS WILL WORK
    let foo: B = Foo; // 2. THIS WILL NOT WORK
    let foo_vec: Vec<B> = vec![Foo]; // 3. THIS WILL NOT WORK
}

This produces the errors:

error[E0308]: mismatched types
  --> src/main.rs:11:18
   |
11 |     let foo: B = Foo; // 2. THIS WILL NOT WORK
   |                  ^^^ expected type parameter, found struct `Foo`
   |
   = note: expected type `B`
              found type `Foo`

error[E0308]: mismatched types
  --> src/main.rs:12:32
   |
12 |     let foo_vec: Vec<B> = vec![Foo]; // 3. THIS WILL NOT WORK
   |                                ^^^ expected type parameter, found struct `Foo`
   |
   = note: expected type `_`
              found type `Foo`

Why won't #2 & #3 work? How can I let the compiler know that Foo does in fact have a Bar impl?


Another examle:

struct Foo<B: Bar> {
    bar: Option<B>,
}

struct Foo2;

trait Bar {}

impl<B: Bar> Bar for Foo<B> {}

impl Bar for Foo2 {}

fn bar<B: Bar>(bar: B) {}

fn circle_vec<B: Bar>() {
    bar(Foo2); // 1. WORKS
    Foo { bar: Some(Foo { bar: None }) }; // 2. WILL NOT WORK
}

This will give me this error:

error[E0282]: type annotations needed
  --> src/main.rs:17:21
   |
17 |     Foo { bar: Some(Foo { bar: None }) }; // 2. WILL NOT WORK
   |                     ^^^ cannot infer type for `B`
like image 712
goo Avatar asked Sep 25 '14 23:09

goo


1 Answers

You have two different problems so I guess I'll write two different answers.


In your first code sample, 2 and 3 don't work because B is an input type parameter; it is the caller of barr that decides what B is. However, you are trying to force it to be Foo.

Let's suppose we have another implementation of Bar:

struct Quux;

impl Bar for Quux {}

And let's suppose we call barr like this:

barr::<Quux>()

barr would essentially be compiled as this:

fn barr() {
    bar(Foo);
    let foo: Quux = Foo;
    let foo_vec: Vec<Quux> = vec![Foo];
}

Foo and Quux are not compatible, and Vec<Foo> and Vec<Quux> are not compatible either.

If you're trying to create a vector of arbitrary Bar objects, you need to use Bar in a non-generic way. As trait types are unsized, you can't store them directly in a Vec, so you must use Vec<Box<Bar>>, Vec<&Bar> or some other type that wraps a pointer.

fn barr() {
    bar(Foo);
    let foo: Box<Bar> = Box::new(Foo);
    let foo_vec: Vec<Box<Bar>> = vec![Box::new(Foo) as Box<Bar>];
}

In your second code sample, the error is that None has the type Option<T>, and the compiler is unable to infer an appropriate type for T. We can explicitly specify T like this:

fn circle_vec<B: Bar>() {
    bar(Foo2);
    Foo {
        bar: Some(Foo { bar: None::<Foo2> }),
    };
}
like image 190
Francis Gagné Avatar answered Nov 14 '22 14:11

Francis Gagné