Подтвердить что ты не робот

Ошибка "ожидаемый тип параметра" в конструкторе общей структуры

Я пытаюсь сохранить текстуры поршня в структуре.

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

Это не скомпилируется:

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 реализует gfx::Resources, хотя (я думаю, что это просто конкретная реализация устройства.) Мне действительно не нравится, какой тип это есть, но мне нужно знать, чтобы я мог хранить его в структуре.

Я сделал компилируемое репо на Github.

(Я подозреваю, ржавые дженерики/черты: "ожидаемый 'Foo <B> ', найденный 'Foo <Foo2 > '" - это тот же самый вопрос, но Я не могу понять, как применить его к моей проблеме.)

4b9b3361

Ответ 1

Вот воспроизведение вашей ошибки:

struct Foo<T> {
    val: T,
}

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

fn main() {}

Проблема возникает потому, что вы пытались лгать компилятору. Этот код:

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

Говорит "Для любого T выберет вызывающий, я создам Foo с этим типом". Затем ваша фактическая реализация выбирает конкретный тип - в примере, bool. Там нет никакой гарантии, что T является bool. Обратите внимание, что ваша new функция даже не принимает никаких параметров типа T, что весьма подозрительно, поскольку вызывающий выбирает конкретный тип в 99% случаев.

Правильный способ сказать это будет

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

Хотя вы, вероятно, хотите выбрать более конкретное имя, чем new, похоже, что вы пытаетесь сделать свою структуру обобщенной. Предположительно были бы другие конструкторы с разными типами.

Для вашего точного кода вы, вероятно, хотите что-то вроде

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

Другое возможное решение - удалить параметр универсального типа из вашей структуры. Если вы когда-нибудь gfx_device_gl::Resources его только с помощью gfx_device_gl::Resources, то нет причин делать его универсальным.

В других случаях вы можете пытаться вернуть тип, который реализует черту. Для этого вы можете использовать объект в штучной упаковке:

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

В будущем вы также сможете использовать impl Trait (он же экзистенциальные типы):

#![feature(existential_type)]

struct Foo<T> {
    val: T,
}

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

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

Смотрите также: