Cannot infer an appropriate lifetime for borrow expression due to conflicting requirement(s)

Viewed 149

I'm having a hard time resolving a lifetime issue:

pub struct A<'a> {
    pub a: &'a str,
    pub b: &'a u8,
}

pub enum Executable<'a> {
    ExecutableA(A<'a>),
}

pub struct Config {
    pub a: String,
    pub b: u8, // some more config values to follow
}

impl Config {
    pub fn new() -> Config {
        // Implementation details omitted due to irrelevancy
        unimplemented!();
    }
}

pub struct Cli<'a> {
    pub config: Config,
    pub execution_list: Vec<Executable<'a>>,
}

impl<'a> Cli<'a> {
    pub fn new() -> Cli<'a> {
        Cli {
            config: Config::new(),
            execution_list: vec![],
        }
    }

    pub fn prepare(&mut self) {
        self.execution_list.push(
            // Compilation error occurs for following line
            Executable::ExecutableA(A {
                a: &self.config.a,
                b: &self.config.b,
            }),
        )
    }
}

The compilation error is:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/lib.rs:39:20
   |
39 |                 a: &self.config.a,
   |                    ^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 35:20...
  --> src/lib.rs:35:20
   |
35 |     pub fn prepare(&mut self) {
   |                    ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:39:20
   |
39 |                 a: &self.config.a,
   |                    ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 27:6...
  --> src/lib.rs:27:6
   |
27 | impl<'a> Cli<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/lib.rs:38:13
   |
38 | /             Executable::ExecutableA(A {
39 | |                 a: &self.config.a,
40 | |                 b: &self.config.b,
41 | |             }),
   | |______________^
   = note: expected `Executable<'a>`
              found `Executable<'_>`

(Playground)

After doing a lot of reading and looking at other questions, I still can't convince myself that I'm understanding the error correctly, mainly because I can't reason why the compiler is attaching the "anonymous" lifetime to the &mut self reference in the prepare function.

My general design idea is that I'll have my Cli struct contain a config, and a list of executables such that I can add all relevant executables to that list in the Cli's prepare function (where I'd like those executables to be able to reference values owned by the Config). I'll then iterate over that execution list to start/stop executables.

I think one answer to this question is to not have executables maintain references to config values and instead copy those values, but I feel like that shouldn't be necessary, and would like to use this issue as a learning opportunity.

I'm totally open to suggestions around "Maybe you should rethink your design and do X, instead."

1 Answers

Anonymous lifetimes are inferred by the compiler, most of them will point to 'static,

If you add this (&'a mut self):

pub fn prepare (&'a mut self) /* ... */ 

It compiles just fine, since the impl lifetime requirement is not conflicting with the Executable one.

Edit:

As pointed out, i was wrong (probably because the rust style did reach into my mind but lifetimes did not), i though about generic lifetimes but i looked at the already existing lifetime 'a and found that it compiled, at least mutably borrowing the class for eternity makes sense.

About your design:

I found it good for what you are trying to do, also i am not the expert with designs, specially in rust, so i found nothing wrong about it.

Viable solution:

Like pointed out, you could add the generic lifetime:

pub fn prepare <'b> (&'b mut self) { ... }

Now whenever the function is called the mutable borrow will last the needed lifetime, and when you want to immutably borrow it, it will work.

Related