在尝试遵循优秀的手工艺翻译书但使用锈蚀代替C的时候遇到了这种情况。
这本书构建了一个基于堆栈的虚拟机,其中我有一个简单的Rust版本,类似于:
struct VM {
stack: Vec<Value>
}
impl VM {
//...
pub fn interpret(op: OpCode) {
match op {
Op::Add => {
let r = self.stack.pop();
let l = self.stack.pop();
self.stack.push(l + r);
}
// Repeated for -, *, and /
}
}
}本书使用C样式宏来防止复制/粘贴所有二进制文件的相同代码。
#define BINOP(op) \
do { \
double r = pop(); \
double l = pop(); \
push(l op r); \
} while (false)
void interpret(VM *vm, OpCode op) {
switch op {
case OP_ADD: BINOP(+); break;
case OP_SUB: BINOP(-); break;
case OP_MUL: BINOP(*); break;
case OP_DIV: BINOP(/); break;
}我试着用Rust宏做类似的事情
macro_rules! binop {
($op:tt) => {
{
let l = self.stack.pop();
let r = self.stack.pop();
self.stack.push(l $op r) };
}
}
// ... inside VM impl ...
pub fn interpret(&mut self, op: OpCode) {
match op {
Op::Add => binop!(+)
// Repeated for -, *, and /
}
}但是宏知道self是什么,我也不知道什么是使宏了解self的最佳方法。
是否有一种方法可以实现类似于Rust中的C宏?
发布于 2021-10-18 04:41:36
您可以将self作为宏的参数传递:
macro_rules! binop {
($self:expr, $op:tt) => {{
let l = $self.stack.pop();
let r = $self.stack.pop();
$self.stack.push(l $op r);
}};
}如果在其他地方不需要宏,也可以在函数中定义宏:
pub fn interpret(&mut self, op: OpCode) {
macro_rules! binop {
($op:tt) => {{
let l = self.stack.pop();
let r = self.stack.pop();
self.stack.push(l $op r);
}};
}
match op {
Op::Add => binop!(+)
// Repeated for -, *, and /
}
}另一种选择可以是使用闭包而不是宏:
impl VM {
pub fn interpret(&mut self, op: OpCode) {
match op {
OpCode::Add => self.binop(|l, r| l + r),
OpCode::Sub => self.binop(|l, r| l - r),
OpCode::Mul => self.binop(|l, r| l * r),
OpCode::Div => self.binop(|l, r| l / r),
}
}
pub fn binop(&mut self, f: impl Fn(Value, Value) -> Value) {
// Of course, in a real case you should handle unwrap:
let l = self.stack.pop().unwrap();
let r = self.stack.pop().unwrap();
self.stack.push(f(l, r));
}
}https://stackoverflow.com/questions/69610395
复制相似问题