&'a mut inside struct<'a> inside another struct<'a>

I can’t make the code below compile. Neither can’t figure out keywords to search through the forum since I’m still new to Rust.

#![allow(dead_code)]

struct Holder<'a> {
    text: &'a mut String,
}
impl<'a> Holder<'a> {
    fn new(text: &'a mut String) -> Self {
        Holder { text }
    }
    fn append(&mut self, suffix: &str) -> () {
        self.text.push_str(suffix);
    }
}

struct SuperHolder<'a> {
    sub_holder: &'a mut Holder<'a>,
}
impl<'a> SuperHolder<'a> {
    fn new(text: &'a mut String) -> SuperHolder<'a> {
        SuperHolder {
            sub_holder: &mut Holder::new(text),
        }
    }
}

fn main() {
    let mut text = String::from("Hello");
    let mut holder = Holder::new(&mut text);
    holder.append(" world");
    println!("{}", holder.text);
}

(Playground)

Errors:

21 |             sub_holder: &mut Holder::new(text),
   |                              ^^^^^^^^^^^^^^^^^ temporary value does not live long enough
22 |         }
23 |     }
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 18:6...
  --> src/lib.rs:18:6
   |
18 | impl<'a> SuperHolder<'a> {
   |      ^^

I understand the error but I don’t know what to do with it. Neither &'mut Holder::new(text), nor &mut Holder<'a>::new(text) compile.

I think you are interested in the following:

struct SuperHolder<'a> {
    sub_holder: Holder<'a>,
}

impl<'a> SuperHolder<'a> {
    fn new(text: &'a mut String) -> SuperHolder<'a> {
        SuperHolder {
            sub_holder: Holder::new(text),
        }
    }
}

Feel free to argue if you were trying to do something different.

Yes, I need something different. Let SuperHolder contain a dyn trait object of Appender which is implemented by Holder. Also assume that trait Appender is from std lib so I can’t modify it. The full example is:

struct Holder<'a> {
    text: &'a mut String,
}
impl<'a> Holder<'a> {
    fn new(text: &'a mut String) -> Self {
        Holder { text }
    }
}

trait Appender {
    fn append(&mut self, suffix: &str) -> ();
}
impl<'a> Appender for Holder<'a> {
    fn append(&mut self, suffix: &str) -> () {
        self.text.push_str(suffix);
    }    
}

struct SuperHolder<'a> {
    sub_holder: &'a mut Appender,
}
impl<'a> SuperHolder<'a> {
    fn new(text: &'a mut String) -> Self {
        SuperHolder {
            sub_holder: &mut Holder::new(text),
        }
    }
}

fn main() {}

https://play.rust-lang.org/?gist=73c4f5274a5caf2af574c8fe6ce486f1&version=stable&mode=debug&edition=2015

Oh, ok.

Then I think you just need to use an owning struct for a dyn Appender. Something like

struct SuperHolder<'a> {
    sub_holder: Box<dyn Appender + 'a>,
}
impl<'a> SuperHolder<'a> {
    fn new(text: &'a mut String) -> Self {
        SuperHolder {
            sub_holder: Box::new(Holder::new(text)),
        }
    }
}

You could also use an Rc instead of the Box, depending on your real-case application.

1 Like