As of today, Rust is not able to express a lifetime that refers to an object defined in the same struct, so it's impossible to declare the proper lifetime for the Device
member.
Instead of storing both objects directly in the struct, could you instead store references to these structs? (This won't work if you want to make a function that returns that struct.)
struct Both<'a: 'b, 'b> {
context: &'a Context,
device: &'b Device<'a>,
}
Another option is to declare the Device
as having a Context
with 'static
lifetime (I'm using 'static
because it's the only lifetime with a name), but always using a method to "cast" the Device
into one with appropriate lifetime parameters, rather than using the field directly.
struct Both {
context: Context,
device: Device<'static>,
}
impl Both {
fn get_device<'a>(&'a self) -> &'a Device<'a> {
&self.device
}
}
Actually, thanks to lifetime elision, it is not necessary to specify the lifetime parameters explicitly on get_device
(likewise for your open_device
method, by the way):
impl Both {
fn get_device(&self) -> &Device {
&self.device
}
}
There's just a gotcha: you need to use transmute
to lie about the device's lifetime parameter when you initialize the struct.
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,
}
}
You might also want to consider having the Both
struct containing a Device
that has no lifetime parameter, then wrapping that in another struct that does have a lifetime parameter and returning that from a method.
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,
}
}
(In fact, the DeviceWrapper
probably doesn't need the _context
member, since the DeviceWrapper
's lifetime is tied to that of the Both
already.)