放入struct时,值的寿命不足 [英] Value doesn't live long enough when put in struct
问题描述
我正在尝试使用此板条箱在Rust中使用LLVM.我试图创建一个代码生成器结构来保存我的上下文,模块和生成器,但是当我尝试编译时,出现一条错误消息,提示c does not live long enough
.我怎样才能编译它?为什么c的生存时间不够长?
I'm trying to work with LLVM in Rust using this crate. I'm trying to create a code generator struct to hold the context, module, and builder for me, but when I try to compile I get an error message that says c does not live long enough
. How can I get this to compile, and why isn't c living 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
推荐答案
这看起来像是一生的遗忘使事情变得不那么清晰的情况之一.
This looks like one of those situations where lifetime elision makes things less clear.
这是原型的Builder::new
:
pub fn new(context: &Context) -> CSemiBox<Builder>
这可能会让您认为CSemiBox
与context
的生存期没有任何关系.但是CSemiBox
的定义具有生命周期参数:
Which might make you think that the CSemiBox
doesn't have any relation to the lifetime of context
. But the definition of CSemiBox
has a lifetime parameter:
pub struct CSemiBox<'a, D>
据我了解,当函数的输出类型(在本例中为Builder::new
)具有有效期参数时,如果只有一个输入有效期,则可以将其删除. (生存期删除规则在这本书和此问题.)在这种情况下,输出生存期与输入生存期相同.这意味着之前的原型实际上等效于以下内容:
As I understand it, when the output type of a function (in this case Builder::new
) has a lifetime parameter, it can be elided if there is only one input lifetime. (The lifetime elision rules are described in the book and in this question.) In this case, the output lifetime is taken to be the same as the input lifetime. That means the prototype from before is actually equivalent to the following:
pub fn new<'a>(context: &'a Context) -> CSemiBox<'a, Builder>
我希望这可以澄清正在发生的事情:在Builder::new(&c)
之后,CSemiBox
包含对其创建的Context
的引用(b
包含对c
的引用).您不能将b
和c
放在相同的结构中,因为编译器必须能够证明c
的寿命超过b
.有关更全面的说明,请参见
I hope this clarifies what's happening: after Builder::new(&c)
, the CSemiBox
contains a reference to the Context
it was created from (b
contains a reference to c
). You can't put b
and c
in the same struct because the compiler has to be able to prove that c
outlives b
. For a more thorough explanation, see Why can't I store a value and a reference to that value in the same struct?
我可以想到两种方法来处理此问题. (您无法使用Rc
,因为您无法控制板条箱.)
There are two ways I can think of to handle this. (You can't use Rc
because you don't control the crate.)
-
不要将
Context
存储在CodeGen
结构中.您在组织代码的方式上受到限制,但这并不一定很糟糕.
Don't store the
Context
inside theCodeGen
struct. You're limited in how you can structure your code, but that's not necessarily bad.
由于Context
存储在堆中,因此可以使用unsafe
使引用(显示为)具有'static
生存期.类似于以下代码片段的代码应该可以正常工作,该代码将从CodeGen
中删除生命周期注释.如果您这样做(随时使用unsafe
),则您有责任确保公开界面的安全性.例如,这意味着CodeGen
无法分发对builder
和module
的引用,因为这可能会泄漏对context
的'static
引用.
Since the Context
is stored on the heap, you can use unsafe
to make the references (appear to) have a 'static
lifetime. Something like the following snippet ought to work, which removes the lifetime annotation from CodeGen
. If you do this (as any time you use unsafe
), you take responsibility for ensuring the safety of the exposed interface. That means, for example, CodeGen
can't hand out references to builder
and module
, because that could leak a 'static
reference to 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,
}
}
}
这篇关于放入struct时,值的寿命不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!