【发布时间】:2022-01-06 16:43:10
【问题描述】:
我很难解决一辈子的问题:
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,
}),
)
}
}
编译错误是:
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<'_>`
经过大量阅读和查看其他问题后,我仍然无法说服自己正确理解错误,主要是因为我无法解释为什么编译器会将“匿名”生命周期附加到&mut self 在prepare 函数中的引用。
我的总体设计理念是让我的Cli 结构包含一个配置和一个可执行文件列表,这样我就可以在Cli 的prepare 函数中将所有相关的可执行文件添加到该列表中(我希望这些可执行文件能够引用Config 拥有的值)。然后,我将遍历该执行列表以启动/停止可执行文件。
我认为这个问题的一个答案是不让可执行文件维护对配置值的引用,而是复制这些值,但我觉得 不应该 是必要的,并且想使用它问题作为学习机会。
我完全愿意接受有关“也许你应该重新考虑你的设计并改用 X”的建议。
【问题讨论】:
-
这只是一个自引用结构,但由于引用和它们引用的值在嵌套结构内部而被伪装。
-
是的,我认为它也是一个自引用结构。话虽如此,那么解决这个问题的“生锈”方法是什么?
-
@SebastianRedl 在发布这个问题之前,我已经阅读了几次该答案 - 我认为它不一定能澄清这个编译错误的任何内容,但这里肯定有一些臭代码。
-
自然地,一个对象的生命周期至少与它所拥有的任何数据的引用一样长。如果
&'a must self不可行,因为它需要太长时间借用,您可以尝试在Config的/A的成员中使用Rc<String>而不是String/&'a str。
标签: rust lifetime borrow-checker