我很难理解什么时候使用可变引用,而不是traits中的不可变引用。
下面的Visitor实现示例取自Rust Design Patterns
:
mod visit {
use ast::*;
pub trait Visitor<T> {
fn visit_name(&mut self, n: &Name) -> T;
fn visit_stmt(&mut self, s: &Stmt) -> T;
fn visit_expr(&mut self, e: &Expr) -> T;
}
}
当不需要在遍历AST时修改节点时,此模式工作得很好。但对于某些用例,在遍历时更改节点可能是一个值得做出的设计选择。
书中的解决方案以文件夹模式的形式出现:
mod fold {
use ast::*;
pub trait Folder {
fn fold_name(&mut self, n: Box<Name>) -> Box<Name> { ... }
fn fold_stmt(&mut self, s: Box<Stmt>) -> Box<Stmt> { ... }
fn fold_expr(&mut self, e: Box<Expr>) -> Box<Expr> { ... }
}
}
类似的事情可以通过简单地使每个AST节点可变来实现。
然而,拥有这两种解决方案似乎是乏味的,而不是维护。对于具有许多不同节点的大型AST,存在大量代码重复;必须为可变节点创建一个Visitor
示例,为非可变节点创建一个示例。有没有更好的方法来实现这种“可选可变性”?
1条答案
按热度按时间yb3bgrhw1#
复制访问者是正确的做法。Rust没有办法抽象引用的可变性,并且有很多这样做的例子,即使在std中(例如。切片迭代器)。如果这是太多的样板,你可以使用宏来帮助它。