没有参考资料,我如何才能拥有终身依赖? [英] How can I have a lifetime dependency without a reference?

查看:82
本文介绍了没有参考资料,我如何才能拥有终身依赖?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在包装一个具有contextdevice对象的C库.由于device保留对context的内部引用,因此context对象需要比device对象更长.

I'm wrapping a C library that has context and device objects. The context object needs to outlive the device object because the device keeps an internal reference to the context.

为此,我在Device包装器中使用了PhantomData字段:

To express this, I use a PhantomData field in the Device wrapper:

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的引用(伪造的),所以我无法做到这一点(请参阅

Now, in my client code, I would like to have a struct that holds both the Context and Device objects. But because the Device holds a reference (a fake one) to the Context, I'm not able to do this (see this question). But this is an unnecessary restriction because the Device struct doesn't actually contain a reference to the Context.

那么如何将Device的生存期与Context的生存期联系起来,以允许我将它们都保存在结构中?

So how can I tie the lifetime of the Device to the lifetime of the Context in a way that would allow me to hold both of them in a struct?

推荐答案

到目前为止,Rust无法表达引用同一结构中定义的对象的生存期,因此无法为该对象声明适当的生存期. Device成员.

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>,
}

另一种选择是将Device声明为具有Context且具有'static的生存期(我正在使用'static,因为它是唯一具有名称的生存期),但始终使用一种方法来铸造"将Device合并为具有适当生存期参数的参数,而不是直接使用该字段.

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
    }
}

实际上,由于使用了生存期删除功能,因此不必在get_device上显式指定生存期参数(顺便说一下,对于您的open_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
    }
}

只有一个陷阱:初始化结构时,您需要使用transmute来了解设备的生命周期参数.

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,
    }
}

您可能还想考虑让Both结构包含一个没有生命周期参数的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,
    }
}

(实际上,DeviceWrapper可能不需要_context成员,因为DeviceWrapper的生存期已经与Both的生存期绑定了.)

(In fact, the DeviceWrapper probably doesn't need the _context member, since the DeviceWrapper's lifetime is tied to that of the Both already.)

这篇关于没有参考资料,我如何才能拥有终身依赖?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆