2016-07-02 6 views
0

Ich bin unglaublich neu in dem Versuch, Generika zu schreiben, und Rust's Eigenschaften entziehen sich meinem Verständnis. Ich habe dieses Stück Code bekam:Probleme beim Verstehen von Merkmalen und Generika in Rust

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 dem ich versuche, ein Merkmal zu definieren, impl dieses Merkmal auf mehrere structs, dann eine Funktion haben, die eine dieser structs zurückgibt. Ist das überhaupt möglich?

Ich erhalte die Compiler-Fehler:

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), 
           ^~~~~~~~~~~~~~~~~~~~~~~~ 

Antwort

0

pub fn choose_mapper<M: Mapper>(rom_header: &RomHeader) -> M bedeutet, dass die Funktion M zurückgibt, die einige (nicht vorhanden) Mapper. Die Generika werden durch den Aufrufer (entweder explizit mit choose_mapper::<SomeM>(foo) oder die meiste Zeit von Kontext wie in let bar: SomeM = choose_mapper(foo) abgeleitet) zur Verfügung gestellt.

Ihre Funktion versucht, eine Mapper1 (das ist einige M, aber nicht unbedingt die gleiche wie die, die der Anrufer will) zurückgeben.

Sie sollten die Signaturen

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

, die die Funktion wählen können, was es gibt.

Interessanterweise gibt es a very active RFC, die einer Funktion erlauben würde, zu wählen, was sie zurückgibt (gewöhnlich impl Trait genannt, obwohl die Syntax noch nicht gewählt wurde).

+0

Das macht Sinn. Soll ich dann Box :: new() in den Match-Armen von Mapper auswählen? oder sollte jeder neue() eine Box zurückgeben? Wenn ich das tue, dann wenn ich versuche, dies in einem anderen Modul zu tun: – cafeclimber

+0

Also klar, ich muss Box :: new() verwenden, wenn ich versuche, choose_mapper von einem anderen Modul aufzurufen und das Ergebnis entweder a zuweisen Variable oder Feld struct, bekomme ich diesen Fehler: nicht in der Lage, genug Typ Informationen über '_'; Typ Anmerkungen oder generische Parameterbindung erforderlich. Ich habe versucht, Casting und geben Sie die Spezifikation ohne Erfolg ... – cafeclimber

+0

Haben Sie '' entfernen? Wenn Sie eine Box zurückgeben, ist die Funktion nicht mehr generisch. – mcarton

Verwandte Themen