0

I need two objects; one object is a container which owns the second object.

struct OuterObject {
    foo: InnerObject,
}

impl OuterObject {
    /// Creates a new instance of OuterObject
    fn new() -> OuterObject {
        OuterObject {
            foo: InnerObject::new(false),
        }
    }

    /// Returns a mutable reference to the InnerObject
    fn get_foo(&mut self) -> &mut InnerObject {
        self.foo
    }
}

struct InnerObject {
    baz: bool,
}

impl InnerObject {
    /// Creates a new instance of InnerObject
    fn new(baz: bool) -> InnerObject {
        InnerObject {
            baz: baz,
        }
    }
}

So far so good. But my InnerObject needs a way to reference the OuterObject that owns it. This means I should pass a reference to the OuterObject into the InnerObject's constructor. But this means the OuterObject's constructor doesn't compile, since self cannot be referenced in a constructor:

struct OuterObject {
    foo: InnerObject,
    vorg: u8,
}

impl OuterObject {
    /// Creates a new instance of OuterObject
    fn new() -> OuterObject {
        OuterObject {
            foo: InnerObject::new(&self, false), // fails; 'self' cannot be referenced in constructor
            vorg: 1,
        }
    }

    /// Returns a mutable reference to the InnerObject
    fn get_foo(&mut self) -> &mut InnerObject {
        self.foo
    }

    /// Returns OuterObject's vorg value
    fn get_vorg(&self) -> u8 {
        self.vorg
    }
}

struct InnerObject {
    blah: &OuterObject
    baz: bool,
}

impl InnerObject {
    fn new(blah: &OuterObject, baz: bool) -> InnerObject {
        InnerObject {
            blah: blah,
            baz: baz,
        }
    }

    /// Calculates something based on the state of the OuterObject that owns this InnerObject
    fn calculate_something(&self) -> u8 {
        self.blah.get_vorg() + 2
    }
}

Next plan: Since I can't reference self in a constructor, I attempted to use lazy loading instead:

struct OuterObject {
    foo: Option<InnerObject>,
    vorg: u8,
}

impl OuterObject {
    /// Creates a new instance of OuterObject
    fn new() -> OuterObject {
        OuterObject {
            foo: None,
            vorg: 1,
        }
    }

    /// Returns a mutable reference to the InnerObject
    fn get_foo(&mut self) -> &mut InnerObject {
        // lazy-loads the object
        if self.foo.is_none() {
            self.foo = Some(InnerObject::new(&self, false));
        }
        self.foo.as_mut().unwrap() // should always be safe
    }

    /// Returns OuterObject's vorg
    fn get_vorg(&self) -> u8 {
        self.vorg
    }
}

struct InnerObject {
    blah: &OuterObject
    baz: bool,
}

impl InnerObject {
    fn new(blah: &OuterObject, baz: bool) -> InnerObject {
        InnerObject {
            blah: blah,
            baz: baz,
        }
    }

    /// Calculates something based on the state of the OuterObject that owns this InnerObject
    fn calculate_something(&self) -> u8 {
        self.blah.get_vorg() + 2
    }
}

Now the compiler is concerned about lifetimes. I have had difficulty finding documentation of how to indicate a lifetime of an object inside of an Option. For instance, if it I write it this way, the compiler things that InnerObject needs to be a trait:

Option<InnerObject + 'a>

1) Is the desired relationship between OuterObject and InnerObject doomed to failure?

2) If not, is there a different design pattern I should be using?

3) If the design pattern I am pursuing is workable, how do I make it work?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
C. Lind
  • 1
  • 2
  • http://stackoverflow.com/q/32300132/155423; http://stackoverflow.com/q/29893978/155423; many others (search circular reference, parent reference, etc.). – Shepmaster Sep 04 '16 at 21:20
  • [One question per question, please](http://meta.stackexchange.com/q/39223/281829). – Shepmaster Sep 04 '16 at 21:20

0 Answers0