Linking functions from different structs, I'm lost!

Hi!
Please, pardon my ignorance. I'm learning Rust. And I couldn't solve this problem. I'm just hitting road blocks with every try.
So what do I want to do?
This is a simulation and in the end an optimisation of a mechanical problem. It is a chain of (mechanical) parts that are unknown at compile time, but loaded from a configuration file. It consists of a set of maybe 5 or so "parts" that share a common set of functions, defined in the TraitAB (all simplified and reduced). The configuration defines what possible parts are actually used and how they are chained together.
So each struct has to be able to call a function of his neighboring object. This does some computation (depending of the type of part) and calls in to his neighbor to the left. When the end is reached, the result is handed back to the originator.

And here is my latest attempt, that is sketchy and most of all does no even compile.

trait TraitAB {
    fn new() -> Self;
    fn set_left(&mut self, left: <dyn TraitAB>);
    fn call_left(&self);
    fn get_x(&self) -> f64;
}

struct PartA {
    x: f64,
    to_my_left: Option<dyn TraitAB>,
}

impl TraitAB for PartA {
    fn new() -> Self {
        PartA {
            x: 0.0,
            to_my_left: None,
        }
    }

    fn set_left(&mut self, left: &<dyn TraitAB>) {
        self.to_my_left = Some(left);
    }

    fn call_left(&self) {
        self.to_my_left.unwrap().get_x();
    }

    fn get_x(&self) -> f64 {
        self.x
    }
}

// PartB looks the same, but actually has a completely different implementation and specific properties that PartA might no have.
struct PartB {
    x: f64,
    to_my_left: Option<dyn TraitAB>,
}

impl TraitAB for PartB {
    fn new() -> Self {
        PartB {
            x: 1.1,
            to_my_left: None,
        }
    }

    fn set_left(&mut self, left: &<dyn TraitAB>) {
        self.to_my_left = Some(left);
    }

    fn call_left(&self) {
        self.to_my_left.unwrap().get_x();
    }

    fn get_x(&self) -> f64 {
        self.x
    }
}

fn test() {
    let mut pa = PartA::new();
    let mut pb = PartB::new();

    pa.set_left(pb);
    pa.call_left();
}

I had the idea to return a set of functions (described in TraitAB) when linking, but failed at passing along the context (the self).
In OOP, all that would be easy with inheritance ...

So how could I make that function link between different structs that share the same trait?
TIA,
Nick

Here's a compiling version of your code:

trait TraitAB {
    fn set_left(&mut self, left: Box<dyn TraitAB>);
    fn call_left(&self);
    fn get_x(&self) -> f64;
}

struct PartA {
    x: f64,
    to_my_left: Option<Box<dyn TraitAB>>,
}

impl PartA {
    fn new() -> Self {
        PartA {
            x: 0.0,
            to_my_left: None,
        }
    }
}

impl TraitAB for PartA {
    fn set_left(&mut self, left: Box<dyn TraitAB>) {
        self.to_my_left = Some(left);
    }

    fn call_left(&self) {
        if let Some(to_my_left) = self.to_my_left.as_ref() {
            to_my_left.get_x();
        }
    }

    fn get_x(&self) -> f64 {
        self.x
    }
}

// PartB looks the same, but actually has a completely different implementation and specific properties that PartA might no have.
struct PartB {
    x: f64,
    to_my_left: Option<Box<dyn TraitAB>>,
}

impl PartB {
    fn new() -> Self {
        PartB {
            x: 1.1,
            to_my_left: None,
        }
    }
}

impl TraitAB for PartB {
    fn set_left(&mut self, left: Box<dyn TraitAB>) {
        self.to_my_left = Some(left);
    }

    fn call_left(&self) {
        if let Some(to_my_left) = self.to_my_left.as_ref() {
            to_my_left.get_x();
        }
    }

    fn get_x(&self) -> f64 {
        self.x
    }
}

fn test() {
    let mut pa = PartA::new();
    let pb = PartB::new();

    pa.set_left(Box::new(pb));
    pa.call_left();
}

If you have any questions regarding the diff for my changes, let me know.

3 Likes

Thanks a lot!
I tried it with Box and it looked similar to what you showed. I even gave it an other try with Box while waiting for a response.
Now I have to see what detail I missed.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.