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<'_>`
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."