我正在包装一个包含context
和device
个对象的C库。 context
对象需要比device
对象更长,因为device
保留了对context
的内部引用。
为了表达这一点,我在PhantomData
包装器中使用Device
字段:
use std::marker::PhantomData;
struct Context;
impl Context {
fn open_device<'a>(&'a self) -> Device<'a> {
Device { _context: PhantomData, }
}
}
struct Device<'a> {
_context: PhantomData<&'a Context>,
}
现在,在我的客户端代码中,我希望有一个包含Context
和Device
对象的结构。但由于Device
拥有Context
的引用(假的),我无法执行此操作(请参阅this问题)。但这是一个不必要的限制,因为Device
结构实际上并不包含对Context
的引用。
那么如何将Device
的生命周期与Context
的生命周期联系起来,以便能够将它们同时保存在结构体中?
答案 0 :(得分:2)
截至今天,Rust无法表达引用同一结构中定义的对象的生命周期,因此无法为Device
成员声明正确的生命周期。
您是否可以存储对这些结构的引用,而不是直接在结构中存储这两个对象? (如果你想创建一个返回该结构的函数,这将无法工作。)
struct Both<'a: 'b, 'b> {
context: &'a Context,
device: &'b Device<'a>,
}
另一种选择是将Device
声明为Context
,其生命周期为'static
(我使用'static
,因为它是唯一的生命周期有一个名字),但总是使用一种方法来&#34;演员&#34;将Device
合并为具有适当生命周期参数的参数,而不是直接使用该字段。
struct Both {
context: Context,
device: Device<'static>,
}
impl Both {
fn get_device<'a>(&'a self) -> &'a Device<'a> {
&self.device
}
}
实际上,由于生命周期的省略,没有必要在get_device
上明确指定生命周期参数(顺便说一下,同样适用于open_device
方法):
impl Both {
fn get_device(&self) -> &Device {
&self.device
}
}
只是一个陷阱:初始化结构时,您需要使用transmute
来说明设备的生命周期参数。
use std::mem;
fn get_both() -> Both {
let context = Context; // could also be a parameter
let device: Device<'static> = unsafe { mem::transmute(context.open_device()) };
Both {
context: context,
device: device,
}
}
您可能还想考虑让包含Both
的{{1}}结构没有生命周期参数,然后将其包装在另一个具有生命周期参数的结构中并从方法中返回。 / p>
Device
(事实上,use std::marker::PhantomData;
use std::mem;
struct Context;
impl Context {
fn open_device(&self) -> Device {
Device
}
}
struct Device;
struct DeviceWrapper<'a> {
_context: PhantomData<&'a Context>,
device: &'a Device,
}
struct Both {
context: Context,
device: Device,
}
impl Both {
fn get_device(&self) -> DeviceWrapper {
DeviceWrapper { _context: PhantomData, device: &self.device }
}
}
fn get_both() -> Both {
let context = Context;
let device = context.open_device();
Both {
context: context,
device: device,
}
}
可能并不需要DeviceWrapper
成员,因为_context
的生命周期与{{1}的生命周期相关联已经。)