【问题标题】:Cannot infer an appropriate lifetime for borrow expression due to conflicting requirement(s) [duplicate]由于需求冲突,无法推断借用表达式的适当生命周期[重复]
【发布时间】: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<'_>`

(Playground)

经过大量阅读和查看其他问题后,我仍然无法说服自己正确理解错误,主要是因为我无法解释为什么编译器会将“匿名”生命周期附加到&amp;mut selfprepare 函数中的引用。

我的总体设计理念是让我的Cli 结构包含一个配置和一个可执行文件列表,这样我就可以在Cliprepare 函数中将所有相关的可执行文件添加到该列表中(我希望这些可执行文件能够引用Config 拥有的值)。然后,我将遍历该执行列表以启动/停止可执行文件。

我认为这个问题的一个答案是不让可执行文件维护对配置值的引用,而是复制这些值,但我觉得 不应该 是必要的,并且想使用它问题作为学习机会。

我完全愿意接受有关“也许你应该重新考虑你的设计并改用 X”的建议。

【问题讨论】:

  • 这只是一个自引用结构,但由于引用和它们引用的值在嵌套结构内部而被伪装。
  • 是的,我认为它也是一个自引用结构。话虽如此,那么解决这个问题的“生锈”方法是什么?
  • @SebastianRedl 在发布这个问题之前,我已经阅读了几次该答案 - 我认为它不一定能澄清这个编译错误的任何内容,但这里肯定有一些臭代码。
  • 自然地,一个对象的生命周期至少与它所拥有的任何数据的引用一样长。如果&amp;'a must self 不可行,因为它需要太长时间借用,您可以尝试在Config 的/A 的成员中使用Rc&lt;String&gt; 而不是String/&amp;'a str

标签: rust lifetime borrow-checker


【解决方案1】:

匿名生命周期由编译器推断,大部分会指向'static

如果你添加这个(&amp;'a mut self):

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

它编译得很好,因为 impl 生命周期要求与 Executable 没有冲突。

编辑:

正如所指出的,我错了(可能是因为 rust 风格确实进入了我的脑海,但生命周期没有),我虽然关于通用生命周期,但我查看了已经存在的生命周期 'a 并发现它编译为最不可变地借用这个类是有道理的。

关于您的设计:

我发现它对你想要做的事情有好处,而且我不是设计专家,特别是在生锈方面,所以我没有发现任何问题。

可行的解决方案:

正如所指出的,您可以添加通用生命周期:

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

现在,每当调用函数时,可变借用将持续所需的生命周期,当您想要不可变地借用它时,它就会起作用。

【讨论】:

  • 编译得很好,但是在获得对self的可变引用时存在一个主要问题> 如果我们有一些结构泛型超过'a,我们几乎不想写一个带有&'a的方法mut自我接收器。我们与 Rust 沟通的是“这种方法将在结构的整个生命周期内可变地借用结构”。在实践中,这意味着 Rust 的借用检查器将只允许在结构永久可变借用并因此不可用之前最多调用一次 some_method。
  • 谢谢,根据您指出的内容进行了编辑,不是很有用,但如果您需要,它就在那里
  • 这个答案也是我的第一个想法,所以我很高兴它记录了这一点,为什么它不起作用。
猜你喜欢
  • 2020-01-29
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 2017-05-07
  • 2021-08-02
  • 2017-07-12
  • 2021-11-02
  • 1970-01-01
相关资源
最近更新 更多