2

I'm having issues understanding how the problem of a self-referencing struct can be solved. Consider the following:

enum Color {
    Brown,
}

struct Pot<'lab> {
    color: Color,
    labels: Vec<&'lab String>,
}

struct Shop<'a> {
    labels: Vec<String>,
    pots: Vec<Pot<'a>>,
}

impl<'a> Shop<'a> {
    fn create_pot(&mut self, label_index: usize) {
        let mut new_pot: Pot<'a> = Pot {
            color: Color::Brown,
            labels: Vec::new(),
        };
        let new_label = &self.labels[label_index];

        new_pot.labels.push(new_label);
        self.pots.push(new_pot);
    }
}

Once I try to compile it, I get this error: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements on self.labels[label_index].

How can I solve this error, knowing that I need Pot to have a reference to a label inside Shop and I need the labels: Vec<String> to stay inside Shop?

trent
  • 25,033
  • 7
  • 51
  • 90
op325
  • 139
  • 1
  • 12
  • Typical solutions might be to split `labels` out from `Shop` so that it's no longer self-referencing, to make `Pot` store indices into the `labels` vector instead of references, or to use `Rc`, which can be cheaply cloned, instead of `String`. – trent Apr 17 '20 at 13:06
  • @trentcl So `Pot::labels` would be a Vec> ? – op325 Apr 17 '20 at 13:24
  • Yes, you could do [something like this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e9115c4e8835d999a4f49bd26120c7ac). `Rc` implements `From` and `From<&str>` so you would probably start with a `String` and convert it. – trent Apr 17 '20 at 13:33
  • @trentcl But how would I get the content of the `Rc` in `Pots::labels` since `Shop::labels` also has a pointer to the same allocation ? For example `Rc::get_mut` would return `None` – op325 Apr 17 '20 at 13:43
  • I don't understand the question? The point of `Rc` is that you can have multiple pointers to the same allocation. It's true you can't mutate the `str` but you can't do that with `&String` either. (aside: [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/q/40006219/3650362) applies here since you can't do anything with a `&String` that you couldn't do with a `&str`.) – trent Apr 17 '20 at 13:50
  • @trentcl for example, how would I `println` the value contained in `Pot::labels[0]` ? – op325 Apr 17 '20 at 14:36
  • Just the same way you would if it were a `String`? `println!("{}", my_pot.labels[0])` – trent Apr 17 '20 at 14:59

0 Answers0