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?