2015-08-19 79 views
2

背景:使用模式匹配結構域之間進行選擇

我想在魯斯特實現一個簡單的虛擬機。目前,我正在致力於支持空間用於字符串和整數的「RegisterBank」。 的RegisterBank結構看起來如下:

pub struct RegisterBank { 
    int_registers: Vec<i32>, 
    str_registers: Vec<String>, 
} 

所以這是兩個向量的只是一個簡單的集合。

以前的工作:

當我試圖實施「負荷」和「存儲」功能,有兩個不同的功能

pub fn load_int(...) { ... } 
pub fn load_str(...) { ... } 

和模式匹配之間的選擇(這是我想要的反正學習)

pub fn load(self, register: SomeMatchableType) { 
    match register { ... } 
} 

因爲有兩個非常相似的任務一個功能看起來不錯,我嘗試了一些東西IKE此:

enum OperandType { 
    Number(i32), 
    Word(String), 
} 

,然後有像pub fn load(self, register: OperandType)的功能相匹配寄存器並返回是一個字符串(或& STR,等等)或根據其操作數類型的整數。

問題: 目前的實施是卡在兩個單獨的函數(對於i32和字符串),這是工作正常。因爲我已經設法爲fn store(&mut self, register: usize, value: OperandType)做到這一點,所以對於fn load(self, register: ???)這也應該是可能的。我最大的問題是設計這樣一個函數,它將兩個任務合併爲一個模式匹配,具體取決於枚舉(或者如果某人有聰明的想法,也許還有其他的東西)。

基本上,解決方案應該做到:

  1. 決定哪一個寄存器(int_registers或str_register)選擇基於輸入參數
  2. 獲取寄存器的內容
  3. 返回它
+1

你可以做一個'enum RegisterType {Number(usize),Word(usize)}' – Adrian

+0

順便說一句,這與你的問題沒有任何關係,但我認爲你的代碼看起來更習慣,如果你重命名'OperandType '只是'操作數' – Adrian

回答

4

load()不可能對輸入參數進行模式匹配,因爲按照定義,它根本沒有可匹配的模式匹配。你似乎真正在尋找的是一種通過返回類型製作load()通用的方法 - 而且你很幸運,因爲Rust實際上可以實現這一點。

您需要創建一個通用的特點,併爲您的覆蓋類型的實現,你的情況i32String

trait LoadFromRegister<T> { 
    fn load(&self, register: usize) -> T; 
} 

impl LoadFromRegister<i32> for RegisterBank { 
    fn load(&self, register: usize) -> i32 { 
     self.int_registers[register] 
    } 
} 

impl LoadFromRegister<String> for RegisterBank { 
    fn load(&self, register: usize) -> String { 
     self.str_registers[register].clone() 
    } 
} 

load可以稱得上既可以由上下文或明確地提供一個返回類型使用海星操作:可用於

let intreg: i32 = rb.load(2); // or, let intreg = rb.load::<i32>(2); 
let strreg: String = rb.load(2); 

類似的技術來擺脫笨重OperandType包裝的。定義一個​​特點,提供store()i32String值類型做了具體的門店實現它爲RegisterBank

trait StoreToRegister<T> { 
    fn store(&mut self, register: usize, value: T); 
} 

impl StoreToRegister<i32> for RegisterBank { 
    fn store(&mut self, register: usize, n: i32) { 
     self.int_registers[register] = n; 
    } 
} 

impl StoreToRegister<String> for RegisterBank { 
    fn store(&mut self, register: usize, s: String) { 
     self.str_registers[register] = s; 
    } 
} 

這提供最接近鏽相當於參數重載,允許main()看起來像這樣:

fn main() { 
    let mut rb = RegisterBank::new(); 
    rb.store(2, 5); 
    rb.store(2, "foo".to_owned()); 
    let intreg: i32 = rb.load(2); 
    let strreg: String = rb.load(2); 
    assert!(intreg == 5); 
    assert!(strreg == "foo"); 
} 

這兩個性狀可合併成一個RegisterStorage特徵,提供loadsave。完整代碼at the playground

相關問題