“Expected type parameter” error in the constructor of a generic struct

為{幸葍}努か 提交于 2019-11-25 23:15:08

问题


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> { /* ... */ }

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.

In other cases, you may be trying to return a type that implements a trait. For that, you can use a boxed trait object:

impl Foo<Box<dyn std::fmt::Display>> {
    fn new() -> Self {
        Foo { val: Box::new(true) }
    }
}

In the future, you may also be able to use impl Trait (a.k.a. existential types):

#![feature(existential_type)]

struct Foo<T> {
    val: T,
}

existential type D: std::fmt::Display;

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

See also:

  • What is the correct way to return an Iterator (or any other trait)?


来源:https://stackoverflow.com/questions/32551177/expected-type-parameter-error-in-the-constructor-of-a-generic-struct

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!