放入struct时,值的存活时间不够长

时间:2017-03-01 17:41:46

标签: struct rust lifetime

我尝试使用this crate在Rust中使用LLVM。我试图创建一个代码生成器结构来为我保存上下文,模块和构建器,但是当我尝试编译时,我收到一条显示c does not live long enough的错误消息。我怎样才能编译这个,为什么不能长寿?

代码:

use llvm::*;
use llvm::Attribute::*;
pub struct CodeGen<'l> {
    context: CBox<Context>,
    builder: CSemiBox<'l, Builder>,
    module: CSemiBox<'l, Module>,
}
impl<'l> CodeGen<'l> {
    pub fn new() -> CodeGen<'l> {
        let c = Context::new();
        let b = Builder::new(&c);
        let m = Module::new("test", &c);
        CodeGen {
            context: c,
            builder: b,
            module: m,
        }
    }
}

完整的错误消息:

error: `c` does not live long enough
  --> src/codegen.rs:17:31
   |
17 |         let b = Builder::new(&c);
   |                               ^ does not live long enough
...
24 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'l as defined on the body at 15:32...
  --> src/codegen.rs:15:33
   |
15 |     pub fn new() -> CodeGen<'l> {
   |                                 ^

error: `c` does not live long enough
  --> src/codegen.rs:18:38
   |
18 |         let m = Module::new("test", &c);
   |                                      ^ does not live long enough
...
24 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'l as defined on the body at 15:32...
  --> src/codegen.rs:15:33
   |
15 |     pub fn new() -> CodeGen<'l> {
   |                                 ^

error: aborting due to 2 previous errors

1 个答案:

答案 0 :(得分:2)

这看起来就像生活中的缺陷使事情变得不那么明显的情况之一。

这里是Builder::new的{​​{3}}:

pub fn new(context: &Context) -> CSemiBox<Builder>

这可能会让您认为CSemiBoxcontext的生命周期没有任何关系。但CSemiBox的{​​{3}}有一个生命周期参数:

pub struct CSemiBox<'a, D>

据我了解,当函数的输出类型(在这种情况下为Builder::new)具有生命周期参数时,如果只有一个输入生命周期,则可以省略它。 (生命周期省略规则在prototypedefinition中描述。)在这种情况下,输出生命周期与输入生命周期相同。这意味着之前的原型实际上等同于以下内容:

pub fn new<'a>(context: &'a Context) -> CSemiBox<'a, Builder>

我希望这可以澄清发生了什么:在Builder::new(&c)之后,CSemiBox包含对其创建的Context的引用(b包含引用到c)。您不能将bc放在同一个结构中,因为编译器必须能够证明c超过b。有关更详尽的说明,请参阅the book

我可以通过两种方式来处理这个问题。 (您无法使用Rc,因为您无法控制箱子。)

  1. 不要将Context存储在CodeGen结构中。您在如何构建代码方面受到限制,但这并不一定是坏事。

  2. 由于Context存储在堆上,您可以使用unsafe使引用(看起来)具有'static生命周期。类似下面的代码段应该有效,它会从CodeGen中删除生命周期注释。如果您这样做(任何时候使用unsafe),您负责确保公开界面的安全性。这意味着,例如,CodeGen无法分发对buildermodule的引用,因为这可能会泄漏对'static的{​​{1}}引用。

    context