如何在Rust中实现Crafting Interpreters的BINARY_OP宏等效功能
问题根因
你写的宏无法识别self是因为Rust采用卫生宏设计,宏内部的标识符不会和调用方作用域的标识符自动绑定,需要显式将self作为参数传入宏,同时你原有的宏里操作数弹出顺序错误,会导致减法、除法这类非交换律运算结果不符合预期。
方案1:调整宏定义实现和C宏等效效果
修正后的宏代码如下:
macro_rules! binop { ($self:ident, $op:tt) => {{ // 先弹右操作数,再弹左操作数,和原书C宏逻辑一致 let r = $self.stack.pop().unwrap(); let l = $self.stack.pop().unwrap(); $self.stack.push(l $op r); }}; }
调用方式:
pub fn interpret(&mut self, op: OpCode) { match op { Op::Add => binop!(self, +), Op::Sub => binop!(self, -), Op::Mul => binop!(self, *), Op::Div => binop!(self, /), } }
如果需要处理栈下溢场景,把代码里的unwrap替换为对应的错误处理逻辑即可。
方案2:更符合Rust风格的零成本无宏实现
不用宏也可以实现完全等效的效果,可读性更好且没有额外性能开销:
// 加inline强制优化,执行效率和宏完全一致 #[inline(always)] fn binop<F: FnOnce(Value, Value) -> Value>(&mut self, op: F) { let r = self.stack.pop().unwrap(); let l = self.stack.pop().unwrap(); self.stack.push(op(l, r)); }
调用方式:
pub fn interpret(&mut self, op: OpCode) { match op { Op::Add => self.binop(|l, r| l + r), Op::Sub => self.binop(|l, r| l - r), Op::Mul => self.binop(|l, r| l * r), Op::Div => self.binop(|l, r| l / r), } }
内容的提问来源于stack exchange,提问作者user9614249
相关产品推荐
相关产品推荐

