2016-07-02 22 views
0

我對嘗試編寫泛型非常陌生,Rust的特徵仍然不能理解。我有這段代碼:難以理解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) {} 
} 

中,我嘗試定義一個特點,實現了一套在幾個結構是特質,然後有它返回的結構的一個功能。這甚至有可能嗎?

我得到的編譯器錯誤:

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

回答

0

pub fn choose_mapper<M: Mapper>(rom_header: &RomHeader) -> M意味着該函數返回M,這是一些(不是所有)Mapper。調用者(或者明確地使用choose_mapper::<SomeM>(foo)或者從let bar: SomeM = choose_mapper(foo)的上下文推斷的大部分時間)提供

你的函數試圖返回一個Mapper1(這是一些M,但不一定與調用者想要的一樣)。

您應該更改簽名

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

,允許選擇它返回的功能。

有趣的是,有a very active RFC這將允許一個函數來選擇它返回的內容(通常稱爲impl Trait,雖然語法尚未選擇)。

+0

這很有道理。那麼我應該使用Box :: new()在選擇映射器的匹配武器中嗎?或者應該每個new()返回一個Box ? 如果我這樣做,那麼如果我嘗試在另一個模塊中執行此操作: – cafeclimber

+0

顯然,我必須使用Box :: new(),當我嘗試從另一個模塊調用choose_mapper並將結果賦值給變量或結構字段,我得到這個錯誤: 無法推斷有關'_'的足夠的類型信息;類型註釋或通用參數綁定。 我已經嘗試鑄造和類型規範無濟於事... – cafeclimber

+0

您是否刪除了''?如果你返回一個盒子,該功能不再是通用的。 – mcarton