
Rust 访问者模式讲解和代码示例
访问者是一种行为设计模式, 允许你在不修改已有代码的情况下向已有类层次结构中增加新的行为。
阅读我们的文章访问者和双分派以了解为什么不能通过方法重载来简单地替换访问者。
Deserialization
A real-world example of the Visitor pattern is serde serialization framework and its deserialization model (see Serde data model).
Visitor
should be implemented for a deserializable type.Visitor
is passed to aDeserializer
(an "Element" in terms of the Visitor Pattern), which accepts and drives theVisitor
in order to construct a desired type.
Let's reproduce this deserializing model in our example.
visitor.rs
use crate::{TwoValuesArray, TwoValuesStruct}; /// Visitor can visit one type, do conversions, and output another type. /// /// It's not like all visitors must return a new type, it's just an example /// that demonstrates the technique. pub trait Visitor { type Value; /// Visits a vector of integers and outputs a desired type. fn visit_vec(&self, v: Vec<i32>) -> Self::Value; } /// Visitor implementation for a struct of two values. impl Visitor for TwoValuesStruct { type Value = TwoValuesStruct; fn visit_vec(&self, v: Vec<i32>) -> Self::Value { TwoValuesStruct { a: v[0], b: v[1] } } } /// Visitor implementation for a struct of values array. impl Visitor for TwoValuesArray { type Value = TwoValuesArray; fn visit_vec(&self, v: Vec<i32>) -> Self::Value { let mut ab = [0i32; 2]; ab[0] = v[0]; ab[1] = v[1]; TwoValuesArray { ab } } }
main.rs
#![allow(unused)] mod visitor; use visitor::Visitor; /// A struct of two integer values. /// /// It's going to be an output of `Visitor` trait which is defined for the type /// in `visitor.rs`. #[derive(Default, Debug)] pub struct TwoValuesStruct { a: i32, b: i32, } /// A struct of values array. /// /// It's going to be an output of `Visitor` trait which is defined for the type /// in `visitor.rs`. #[derive(Default, Debug)] pub struct TwoValuesArray { ab: [i32; 2], } /// `Deserializer` trait defines methods that can parse either a string or /// a vector, it accepts a visitor which knows how to construct a new object /// of a desired type (in our case, `TwoValuesArray` and `TwoValuesStruct`). trait Deserializer<V: Visitor> { fn create(visitor: V) -> Self; fn parse_str(&self, input: &str) -> Result<V::Value, &'static str> { Err("parse_str is unimplemented") } fn parse_vec(&self, input: Vec<i32>) -> Result<V::Value, &'static str> { Err("parse_vec is unimplemented") } } struct StringDeserializer<V: Visitor> { visitor: V, } impl<V: Visitor> Deserializer<V> for StringDeserializer<V> { fn create(visitor: V) -> Self { Self { visitor } } fn parse_str(&self, input: &str) -> Result<V::Value, &'static str> { // In this case, in order to apply a visitor, a deserializer should do // some preparation. The visitor does its stuff, but it doesn't do everything. let input_vec = input .split_ascii_whitespace() .map(|x| x.parse().unwrap()) .collect(); Ok(self.visitor.visit_vec(input_vec)) } } struct VecDeserializer<V: Visitor> { visitor: V, } impl<V: Visitor> Deserializer<V> for VecDeserializer<V> { fn create(visitor: V) -> Self { Self { visitor } } fn parse_vec(&self, input: Vec<i32>) -> Result<V::Value, &'static str> { Ok(self.visitor.visit_vec(input)) } } fn main() { let deserializer = StringDeserializer::create(TwoValuesStruct::default()); let result = deserializer.parse_str("123 456"); println!("{:?}", result); let deserializer = VecDeserializer::create(TwoValuesStruct::default()); let result = deserializer.parse_vec(vec![123, 456]); println!("{:?}", result); let deserializer = VecDeserializer::create(TwoValuesArray::default()); let result = deserializer.parse_vec(vec![123, 456]); println!("{:?}", result); println!( "Error: {}", deserializer.parse_str("123 456").err().unwrap() ) }
Output
Ok(TwoValuesStruct { a: 123, b: 456 }) Ok(TwoValuesStruct { a: 123, b: 456 }) Ok(TwoValuesArray { ab: [123, 456] }) Error: parse_str unimplemented