访问者模式介绍
访问者是一种设计模式,它允许向对象集合添加新操作,而不需要修改对象本身,这一点很重要。如果你想在Rust中实现Visitor模式,你可以使用trait来实现。首先我们来看一下基本结构:

1,在访问者界面中实现访问(visit)功能,这确保元素可以被访问。
2,在Element中实现接受(accept)功能。这确保当访问Element时,可以执行操作。
在Rust中的实现访问者模式
新建一个Rust项目:
cargo new rust_visitor
我们首先定义Visitor trait:
pub trait Visitor {
fn visit_person(&self, person:&Person);
fn visit_organization(&self, o:&Organization);
}
然后是Element trait:
pub trait Element {
fn accept(&self, visitor: &mut dyn Visitor);
}
在我们的例子中,我们可以访问Person和Organization,我们将从Person开始:
pub struct Person {
email: String,
name: String,
}
// 堆代码 duidaima.com
impl Element for Person {
fn accept(&self, visitor: &mut dyn Visitor) {
visitor.visit_person(self);
}
}
impl Person {
fn new(name:&str, email:&str)->Self {
Self {
email: email.to_string(),
name: name.to_string()
}
}
}
1,首先,我们为Person结构体实现Element特征。很明显,它所做的就是调用visit_person方法并将Person对象作为参数传递。
2,接下来是构造函数的实现。我使用&str来防止生命周期问题。注意,Self指的是实现类型。
现在看看Organization结构体的实现:
pub struct Organization {
name: String,
address: String
}
impl Element for Organization {
fn accept(&self, visitor: &mut dyn Visitor) {
visitor.visit_organization(self);
}
}
impl Organization {
fn new(name: &str, address:&str)->Self {
Self {
name: name.to_string(),
address: address.to_string()
}
}
}
访问者是client,我们将实现一个非常简单的例子:
struct EmailVisitor;
impl Visitor for EmailVisitor {
fn visit_person(&self, p:&Person) {
println!("Sending email to {} at {}",p.name,p.email);
}
fn visit_organization(&self, o:&Organization) {
println!("Sending mail to {} at {}",o.name,o.address);
}
}
在这个简化示例中,EmailVisitor定义为空结构体。
测试
fn main() {
let mut elements:Vec<Box<dyn Element>>=Vec::new();
let alice=Box::new(Person::new("Alice", "alices@example.com"));
let bob=Box::new(Person::new("Bob", "bob@example.com"));
let acme=Box::new(Organization::new("Acme Inc.","123 Main Str."));
elements.push(alice);
elements.push(acme);
elements.push(bob);
let mut email_visitor=EmailVisitor;
for element in elements {
element.accept(&mut email_visitor);
}
}
1,首先,我们定义一个Vector元素,其类型为Vec<Box<dyn Element>>。为什么是dyn Element?因为Element是一个trait,需要动态调度,因为我们不知道要存储的元素的大小。毕竟,我们只知道它们实现了Element特性。
2,接下来,我们实例化三个结构体,一个Organization和两个Persons,我们将它们push到Vector上。
3,我们实例化了EmailVisitor。
4,通过调用accept方法遍历元素并访问它们。
执行cargo run,结果如下:
Sending email to Alice at alices@example.com
Sending mail to Acme Inc. at 123 Main Str.
Sending email to Bob at bob@example.com