generics rust traits

generics - Error de "parámetro de tipo esperado" en el constructor de una estructura genérica



rust traits (1)

Estoy tratando de almacenar texturas de pistón en una estructura.

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

Esto no compila:

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 implementa gfx::Resources (creo que es solo la implementación específica del dispositivo). En realidad no me importa de qué tipo es, pero necesito saberlo para poder almacenarlo en la estructura.

Hice un repositorio compilable en Github .

(Sospecho de Rust generics / rasgos: "esperado ''Foo <B>'', encontrado ''Foo <Foo2>''" es la misma pregunta, pero no puedo entender cómo aplicarlo a mi problema).


Aquí hay una reproducción de su error:

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

El problema surge porque trataste de mentirle al compilador. Este código:

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

Dice "Para cualquier T elija la persona que llama , crearé un Foo con ese tipo". Luego, su implementación real elige un tipo concreto , en el ejemplo, un bool . No hay garantía de que T sea ​​un bool . Tenga en cuenta que su new función ni siquiera acepta ningún parámetro de tipo T , lo cual es altamente sospechoso, ya que así es como la persona que llama elige el tipo concreto el 99% del tiempo.

La forma correcta de decir esto sería

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

Aunque probablemente desee elegir un nombre más específico que new , ya que parece que está tratando de hacer que su estructura sea genérica. Presumiblemente habría otros constructores con diferentes tipos.

Para su código exacto, probablemente quiera algo como

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

Otra posible solución sería eliminar el parámetro de tipo genérico de su estructura. Si solo lo construyes con un gfx_device_gl::Resources , entonces no hay razón para hacerlo genérico.

En otros casos, puede estar intentando devolver un tipo que implemente un rasgo. Para eso, puede usar un objeto de rasgo en caja:

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

En el futuro, también puede usar el impl Trait (también conocido como tipos existenciales ):

#![feature(existential_type)] struct Foo<T> { val: T, } existential type D: std::fmt::Display; impl Foo<D> { fn new() -> Self { Foo { val: true } } }

Ver también:

  • ¿Cuál es la forma correcta de devolver un iterador (o cualquier otro rasgo)?