“Expected type parameter” error in the constructor

2019-01-01 04:06发布

问题:

I am trying to store piston textures in a struct.

struct TextureFactory<R> where R: gfx::Resources {
    block_textures: Vec<Rc<Texture<R>>>,
}

impl<R> TextureFactory<R> where R: gfx::Resources  {
    fn new(window: PistonWindow) -> Self {
        let texture = Rc::new(gfx_texture::Texture::from_path(
            &mut *window.factory.borrow_mut(),
            \"assets/element_red_square.png\",
            Flip::None, &TextureSettings::new()
        ).unwrap());
        let block_textures = Vec::new();
        block_textures.push(texture);

        TextureFactory {
            block_textures: block_textures,
        }
    }
}

This does not compile:

src/main.rs:37:9: 39:10 error: mismatched types:
 expected `TextureFactory<R>`,
    found `TextureFactory<gfx_device_gl::Resources>`
(expected type parameter,
    found enum `gfx_device_gl::Resources`)

gfx_device_gl::Resources implements gfx::Resources though (I think it\'s just the device specific implementation.) I don\'t actually care what type this is, but I need to know so that I can store it in the struct.

I made a compilable repo on Github.

(I suspect Rust generics/traits: "expected 'Foo<B>', found 'Foo<Foo2>'" is the same question, but I can\'t figure out how to apply it to my problem.)

回答1:

Here\'s a reproduction of your error:

struct Foo<T> {
    val: T,
}

impl<T> Foo<T> {
    fn new() -> Self {
        Foo { val: true }
    }
}

fn main() {

}

The problem arises because you tried to lie to the compiler. This code:

impl<T> Foo<T> {
    fn new() -> Self {}
}

Says \"For whatever T the caller chooses, I will create a Foo with that type\". Then your actual implementation picks a concrete type — in the example, a bool. There\'s no guarantee that T is a bool. Note that your new function doesn\'t even accept any parameter of type T, which is highly suspect as that\'s how the caller picks the concrete type 99% of the time.

The correct way of saying this would be

impl Foo<bool> {
    fn new() -> Self {
        Foo { val: true }
    }
}

Although you probably want to pick a more specific name than new, as it looks as if you are trying to make your struct generic. Presumably there would be other constructors with different types.

For your exact code, you probably want something like

impl TextureFactory<gfx_device_gl::Resources> { ... }

Of course, another possible solution would be to remove the generic type parameter from your struct. If you only ever construct it with a gfx_device_gl::Resources, then there\'s no reason to make it generic.