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)?