Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visitor pattern in Rust

Tags:

rust

I found an interesting implementation of the visitor pattern in Rust:

pub trait Visitor<T> {
    fn visit(&mut self, t: &T);
}

pub trait Visitable: Sized {
    fn accept<T>(&self, t: &mut T)
    where
        T: Visitor<Self>,
    {
        t.visit(self);
    }
}

As Visitable is not object safe, I'm unable to store a Vec of Visitable objects. I found a solution to a similar problem, would it be possible to do a similar solution for Visitable?

like image 216
prinsen Avatar asked Feb 15 '26 01:02

prinsen


1 Answers

Visitable is a trait and traits have no size (implementors are not guaranteed to have the same size). You need to store something that has a size. Wrap the values in a Box and then use it like following:

trait VisitorTrait {
    fn visit(&self, visitable: &Box<VisitableTrait>);
}

struct Visitor1 {}
struct Visitor2 {}

impl VisitorTrait for Visitor1 {
    fn visit(&self, visitable: &Box<VisitableTrait>) {
        println!("visited via Visitor1");
        visitable.accept()
    }
}

impl VisitorTrait for Visitor2 {
    fn visit(&self, visitable: &Box<VisitableTrait>) {
        println!("visited via Visitor2");
        visitable.accept()
    }
}

trait VisitableTrait {
    fn accept(&self);
}

#[derive(Clone)]
struct Visitable1 {}
#[derive(Clone)]
struct Visitable2 {}

impl VisitableTrait for Visitable1 {
    fn accept(&self) {
        println!("accepted1.");
    }
}

impl VisitableTrait for Visitable2 {
    fn accept(&self) {
        println!("accepted2.");
    }
}

fn main() {
    let visitor1 = Visitor1 {};
    let visitor2 = Visitor2 {};
    let visitable1 = Visitable1 {};
    let visitable2 = Visitable2 {};

    let mut visitors: Vec<Box<VisitorTrait>> = Vec::new();
    let mut visitables: Vec<Box<VisitableTrait>> = Vec::new();

    visitors.push(Box::new(visitor1));
    visitors.push(Box::new(visitor2));

    visitables.push(Box::new(visitable1));
    visitables.push(Box::new(visitable2));

    for visitable in visitables.iter() {
        for visitor in visitors.iter() {
            visitor.visit(visitable.clone());
        }
    }
}

Playground

We declare two different traits for visitor and the visitables and traversing the visitables with the help of visitors with two for loops.

like image 130
Akiner Alkan Avatar answered Feb 16 '26 16:02

Akiner Alkan