简体   繁体   中英

Having trouble understanding traits and generics in Rust

I'm incredibly new to trying to write generics, and Rust's traits continue to elude my understanding. I've got this piece of code:

pub trait Mapper {
    fn prg_rom_read(&self, addr: u16) -> u8 {}
    fn prg_rom_write(&mut self, addr: u16, val: u8) {}
    fn chr_rom_read(&self, addr: u16) -> u8 {}
    fn chr_rom_write(&mut self, addr: u16, val: u8) {}
}

pub fn choose_mapper<M: Mapper>(rom_header: &RomHeader) -> M {
    match rom_header.mapper_number {
        0 => Mapper1::new(rom_header),
        _ => panic!("Unsupported mapper: {:#}", rom_header.mapper_number),
    }
}

struct Mapper1 {
    prg_ram: Box<[u8]>,
    prg_rom: Box<[u8]>,
    chr: Box<[u8]>,
}

impl Mapper1 {
    pub fn new(rom_header: &RomHeader) -> Self {
        Mapper1 {
            prg_ram: {
                let size = rom_header.prg_ram_size as usize * 8192;
                vec![0; size].into_boxed_slice()
            },
            prg_rom: {
                let size = rom_header.prg_rom_size as usize * 16384;
                vec![0; size].into_boxed_slice()
            },
            chr: {
                let size = rom_header.chr_rom_size as usize * 8192;
                vec![0; size].into_boxed_slice()
            },
        }
    }
}

impl Mapper for Mapper1 {
    fn prg_rom_read(&self, addr: u16) -> u8 {}

    fn prg_rom_write(&mut self, addr: u16, val: u8) {}

    fn chr_rom_read(&self, addr: u16) -> u8 {}

    fn chr_rom_write(&mut self, addr: u16, val: u8) {}
}

in which I try to define a trait, impl that trait on several structs, then have a function which returns one of those structs. Is this even possible?

I get the compiler error:

expected `_`,
    found `mapper::Mapper1`
(expected type parameter,
    found struct `mapper::Mapper1`) [E0308]
src/mapper.rs:11     match rom_header.mapper_number {
src/mapper.rs:12         0 => Mapper1::new(rom_header),
src/mapper.rs:13         _ => panic!("Unsupported mapper: {:#}", rom_header.mapper_number),
src/mapper.rs:14     }
src/mapper.rs:11:5: 14:6 help: run `rustc --explain E0308` to see a detailed explanation
src/mapper.rs:12:14: 12:38 note: match arm with an incompatible type
src/mapper.rs:12         0 => Mapper1::new(rom_header),
                              ^~~~~~~~~~~~~~~~~~~~~~~~

pub fn choose_mapper<M: Mapper>(rom_header: &RomHeader) -> M means that the function returns M , which is some (not any) Mapper . The generics are provided by the caller (either explicitly with choose_mapper::<SomeM>(foo) or most of the time inferred from context as in let bar: SomeM = choose_mapper(foo) ).

Your function tries to return a Mapper1 (which is some M , but not necessarily the same as the one the caller wants).

You should change the signatures to

pub fn choose_mapper(rom_header: &RomHeader) -> Box<Mapper>;

which allows the function to choose what it returns.

Interestingly there is a very active RFC which would allow a function to choose what it returns (usually referred as impl Trait , although the syntax has not been chosen yet).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM