如果没有参考,我怎么能有一生的依赖?

时间:2015-10-18 19:25:28

标签: rust lifetime

我正在包装一个包含contextdevice个对象的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>,
}

现在,在我的客户端代码中,我希望有一个包含ContextDevice对象的结构。但由于Device拥有Context的引用(假的),我无法执行此操作(请参阅this问题)。但这是一个不必要的限制,因为Device结构实际上并不包含对Context的引用。

那么如何将Device的生命周期与Context的生命周期联系起来,以便能够将它们同时保存在结构体中?

1 个答案:

答案 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}的生命周期相关联已经。)