背景:
我正在尝试用 Rust 实现一个简单的虚拟机。目前,我正在开发一个支持字符串和整数空间的“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 { ... }
}
因为用一个函数来完成两个非常相似的任务似乎很好,所以我尝试了这样的方法:
enum OperandType {
Number(i32),
Word(String),
}
然后有一个类似 pub fn load(self, register: OperandType)
的函数它匹配寄存器并返回一个字符串(或&str,等等)或一个整数,具体取决于其操作数类型。
问题:
目前,该实现停留在两个单独的函数(i32 和 String)上,并且工作正常。因为我已经成功地为 fn store(&mut self, register: usize, value: OperandType)
做到了这一点对于 fn load(self, register: ???)
这应该是可能的以及。我最大的问题是设计这样一个函数,根据 OperandType
将两个任务组合成一个模式匹配。枚举(或者如果有人有聪明的想法,可能是其他东西)。
基本上,解决方案应该这样做:
- 根据输入参数决定选择哪个寄存器(int_registers或str_register)
- 获取寄存器的内容
- 返回
最佳答案
load()
不可能对输入参数进行模式匹配,因为根据定义,它根本没有可以匹配的参数。您似乎真正正在寻找的是一种通过返回类型使 load()
通用的方法 - 而且您很幸运,因为 Rust 实际上使这成为可能。
您需要创建一个通用特征并为您所涵盖的类型提供实现,在您的情况下i32
和String
:
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()
的 StoreToRegister
特征,并使用 i32
和 String< 为
执行具体存储的值类型: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;
}
}
这提供了与参数重载最接近的 Rust 等效项,允许 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
特征。完整代码at the playground .
关于rust - 使用模式匹配在结构字段之间进行选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32106850/