0

I'd like to initialize a Rust struct with types that depend on each other, i.e. the last struct field depends on a variable constructed for another field.

Example

You can also find the (hopefully?) minimal reproducible example in this Rust playground.

My structs:

pub struct NeedToRelyOnThis {
}

pub struct Breaking {
}

impl Breaking {
    pub fn new() -> Self {
        Self {}
    }
}

pub struct Depending<'a> {
    needed: &'a NeedToRelyOnThis,
    breaking: &'a Breaking
}

impl<'a> Depending<'a> {
    pub fn new(needed: &'a NeedToRelyOnThis, breaking: &'a Breaking) -> Self {
        Self { needed, breaking }
    }
}

This is working fine:

pub struct BaseWorking<'a> {
    needed: &'a NeedToRelyOnThis,
    d: Depending<'a>
}

impl<'a> BaseWorking<'a> {
    pub fn new(needed: &'a NeedToRelyOnThis, breaking: &'a Breaking) -> Self {
        Self { 
            needed,
            d: Depending::new(needed, breaking)
        }
    }
}

While this is not:

pub struct BaseBroken<'a> {
    needed: &'a NeedToRelyOnThis, // by reference is necessary
    breaking: Breaking,
    d: Depending<'a>
}

impl<'a> BaseBroken<'a> {
    // compile without this function and there won't be any errors
    pub fn new(needed: &'a NeedToRelyOnThis) -> Self {
        Self { 
            needed,
            breaking: Breaking::new(),
            // here I want to pass in a reference to the newly created instance of
            // `Breaking` into the "constructor" of `Depending`
            // It fails as the variable "breaking" cannot be found which is understandable.
            d: Depending::new(needed, breaking) }
   }
}

Context & my attempts

I've seen this question, however I don't understand how I can apply the only answer to my problem.

If it was possible to defer initialization, I could do something like this:

pub fn new(needed: &'a NeedToRelyOnThis) -> Self {
        let mut res = Self { 
            needed,
            breaking: Breaking::new()
        }
        res.d = Depending::new(needed, &res.breaking);
        res
   }

which does not work as we have to initialize all struct field at once. Creating it from parts as seen in this playground founders on borrowed values not living long enough. (I found the playground from this comment).

Background: In my code the BaseBroken struct is a struct implementing an algorithm. NeedToRelyOnThis is a mathematical graph that gets passed to the algorithm from outside (here the variable needed). The algorithm class holds some fields to outsource some calculations. One type needs a reference to the other type to access certain information during the calculation.

I'm open for answers proposing a better design concerning the hierarchy of these structs should it turn out that this is really not easily achievable in Rust. In Java and other languages, it'd be possible to do this since the fields of the class/struct can be set one after the other in a proper constructor, but of course Rust is not Java ;)

Splines
  • 550
  • 1
  • 6
  • 17
  • 1
    The latter attempts to create a *self-referential struct*, which can't really be expressed with Rust's lifetimes. See [Why can't I store a value and a reference to that value in the same struct?](/q/32300132/2189130). – kmdreko Jul 16 '23 at 19:53
  • @kmdreko Thanks, the linked question does indeed answer my question – Splines Jul 17 '23 at 11:21

0 Answers0