当放入结构中时,值的寿命不够长

2023-11-30

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

Code:

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

这看起来像是生命周期省略使事情变得不那么清晰的情况之一。

这是原型 of Builder::new:

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

这可能会让你认为CSemiBox与生命周期没有任何关系context。但是定义 of CSemiBox有一个生命周期参数:

pub struct CSemiBox<'a, D>

据我了解,当函数的输出类型(在本例中)Builder::new) 有一个生命周期参数,如果只有一个输入生命周期,则可以省略该参数。 (生命周期省略规则描述于the book and in 这个问题.) 在这种情况下,输出寿命被认为与输入寿命相同。这意味着之前的原型实际上相当于以下内容:

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

我希望这能澄清发生的事情:之后Builder::new(&c), the CSemiBox包含对Context它是从 (b包含对c)。你不能把b and c在同一个结构中,因为编译器必须能够证明c比寿命长b。有关更彻底的解释,请参阅为什么我不能在同一结构中存储值和对该值的引用?

我可以想到两种方法来处理这个问题。 (你不能使用Rc因为你无法控制箱子。)

  1. 不要存储Context在 - 的里面CodeGen结构。您构建代码的方式受到限制,但这并不一定是坏事。

  2. 自从Context存储在堆上,您可以使用unsafe使参考文献(看起来)具有'static寿命。像下面的代码片段这样的东西应该可以工作,它将生命周期注释从CodeGen。如果你这样做(就像任何时候你使用unsafe), 您负责确保暴露接口的安全。这意味着,例如,CodeGen无法提供参考资料builder and module,因为这可能会泄漏'static参考context.

    pub struct CodeGen {
        context: CBox<Context>,
        builder: CSemiBox<'static, Builder>,
        module: CSemiBox<'static, Module>,
    }
    impl CodeGen {
        pub fn new() -> CodeGen {
            let c = Context::new();  // returns a CBox<Context>
            let c_static_ref: &'static _ = unsafe {
                let c_ptr = c.as_ptr() as *const _;  // get the underlying heap pointer
                &*c_ptr
            };
            let b = Builder::new(c_static_ref);
            let m = Module::new("test", c_static_ref);
            CodeGen {
                context: c,
                builder: b,
                module: m,
            }
        }
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当放入结构中时,值的寿命不够长 的相关文章

随机推荐