Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - "expected type parameter, found struct"

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`
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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> }),
    };
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...