0

I have the following code:

#[derive(Debug)]
struct S<'a> {
    pub ss: Vec<String>,
    pub rs: Vec<&'a str>, // each element in rs is a reference to the corresponding element in ss
}

impl<'a> S<'a> {
    pub fn new() -> Self {
        Self { ss: Vec::new(), rs: Vec::new() }
    }
    
    pub fn push(&mut self, s: String) {
        self.ss.push(s);
        self.rs.push(self.ss.last().unwrap());
    }
}

fn main() {
    let mut x = S::new();
    let s = String::from("hello");
    x.push(s);

    // XXX: the following works!
    // x.ss.push(s);
    // x.rs.push(x.ss.last().unwrap());

    // println!("hello world: {:#?}", x);
}

And the compiler generates the error:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:14:30
   |
14 |         self.rs.push(self.ss.last().unwrap());
   |                              ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/main.rs:12:17
   |
12 |     pub fn push(&mut self, s: String) {
   |                 ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:14:22
   |
14 |         self.rs.push(self.ss.last().unwrap());
   |                      ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/main.rs:7:6
   |
7  | impl<'a> S<'a> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:14:22
   |
14 |         self.rs.push(self.ss.last().unwrap());
   |                      ^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground` due to previous error

However, the two lines below XXX does work!

How can I make the compiler happy?

Rust Playground

[EDIT]: of course, I have to admit that the design is flawed - what if an element is removed from ss, then without other compiler aware guarantees, the corresponding reference in rs would become dangling - the compiler can only be conservative here as to reject the code above. But, what about using unsafe Rust to achieve that, if the programmer can provide the safety guarantee?

Dejavu
  • 1,299
  • 14
  • 24
  • 1
    You're basically running into the age-old problem of self-referential structs in Rust; for your case you could cheat and use one of the common suggestions of keeping a vector of indexes that reference the index of the strings in `ss`. See: https://stackoverflow.com/questions/32300132/why-cant-i-store-a-value-and-a-reference-to-that-value-in-the-same-struct – Martin Gallagher Dec 04 '21 at 09:51
  • 1
    Does this answer your question? [Structs with slices pointing to data in themselves](https://stackoverflow.com/questions/27294539/structs-with-slices-pointing-to-data-in-themselves) – Chayim Friedman Dec 05 '21 at 18:56
  • I think @MartinGallagher's link is more accurate. But why the two lines below XXX works? – Dejavu Dec 06 '21 at 11:10
  • `x.ss.last().unwrap()` is a `&str` for the lifetime of `main()` - `x = S::new()`'s lifetime is the same, both are dropped at the end of `main()`; in that instance the compiler can deduce there would be no lifetime infringement. – Martin Gallagher Dec 07 '21 at 07:35

0 Answers0