如何确保对象的寿命不会超过其工厂

发布于 2025-01-10 09:55:45 字数 633 浏览 1 评论 0原文

假设我有一个对象工厂:

struct Object;
struct Factory;

impl Object {
    pub fn new() -> Object { Object{} }
}

impl Factory {
    pub fn new() -> Factory { Factory{} }
    pub fn create() -> Object { Object::new() }
}

如何确保工厂创建的对象不会比工厂寿命更长?换句话说,如何使这样的代码无法编译:

let factory = Factory::new();
let object = factory.create();
drop(factory); // Some kind of lifetime compile error

只要编译器知道发生了什么,就可以随意使用任何包装器/容器来跟踪所有内容。我自己尝试过返回很多不同的东西,包括 &RefCell,但我总是碰壁并最终重新开始。

Lets say I have a factory of objects:

struct Object;
struct Factory;

impl Object {
    pub fn new() -> Object { Object{} }
}

impl Factory {
    pub fn new() -> Factory { Factory{} }
    pub fn create() -> Object { Object::new() }
}

How can you ensure that objects created by the factory do no outlive the factory? In other words, how to make code like this not compile:

let factory = Factory::new();
let object = factory.create();
drop(factory); // Some kind of lifetime compile error

Feel free to use any wrappers/containers to keep track of everything, as long as the compiler knows that something's up. I have tried returning a lot of different things myself, including &RefCell<Object>, but I always run into a wall and end up starting over.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月静好 2025-01-17 09:55:45

Rust 有一个生命周期/借用检查机制,以确保引用不会比被引用对象的寿命更长。您可以使用相同的原则来保证对象的寿命不会超过其工厂的寿命。您所需要的只是 Object 有一个绑定到 Factory 的生命周期注释,如下所示(游乐场):

#[derive(Debug)]
struct Factory;

#[derive(Debug)]
struct Object<'a> {
    // You can keep a reference to the factory if that's useful
    factory: &'a Factory,
    
    // Or you can save the bytes by using PhantomData instead
    // dummy: PhantomData<&'a Factory>,
}

impl Object<'_> {
    pub fn new(factory: &Factory) -> Object<'_> { Object { factory } }
}

impl Factory {
    pub fn new() -> Factory { Factory {} }
    pub fn create(&self) -> Object<'_> { Object::new(self) }
}

fn main() {
    let factory = Factory::new();
    let object = factory.create();
    drop(factory);

    // Just dropping the factory wouldn't cause an error unless the Object had
    // a Drop implementation or was used after the factory was dropped, so
    // trying to "use" the object by printing it after the factory was dropped
    // won't be allowed
    println!("{:?}", object);
}
error[E0505]: cannot move out of `factory` because it is borrowed
  --> src/main.rs:25:10
   |
24 |     let object = factory.create();
   |                  ---------------- borrow of `factory` occurs here
25 |     drop(factory);
   |          ^^^^^^^ move out of `factory` occurs here
26 | 
27 |     println!("{:?}", object);
   |                      ------ borrow later used here

Rust has a lifetime/borrow-checking mechanism to ensure references do not outlive the referenced object. You can use the same principles to guarantee that Objects do not outlive their Factory. All you need is for Object to have a lifetime annotation that is bound to the Factory like so (playground):

#[derive(Debug)]
struct Factory;

#[derive(Debug)]
struct Object<'a> {
    // You can keep a reference to the factory if that's useful
    factory: &'a Factory,
    
    // Or you can save the bytes by using PhantomData instead
    // dummy: PhantomData<&'a Factory>,
}

impl Object<'_> {
    pub fn new(factory: &Factory) -> Object<'_> { Object { factory } }
}

impl Factory {
    pub fn new() -> Factory { Factory {} }
    pub fn create(&self) -> Object<'_> { Object::new(self) }
}

fn main() {
    let factory = Factory::new();
    let object = factory.create();
    drop(factory);

    // Just dropping the factory wouldn't cause an error unless the Object had
    // a Drop implementation or was used after the factory was dropped, so
    // trying to "use" the object by printing it after the factory was dropped
    // won't be allowed
    println!("{:?}", object);
}
error[E0505]: cannot move out of `factory` because it is borrowed
  --> src/main.rs:25:10
   |
24 |     let object = factory.create();
   |                  ---------------- borrow of `factory` occurs here
25 |     drop(factory);
   |          ^^^^^^^ move out of `factory` occurs here
26 | 
27 |     println!("{:?}", object);
   |                      ------ borrow later used here
冷︶言冷语的世界 2025-01-17 09:55:45

在对象中保留对工厂的引用。这将使得在删除(或改变)factory 的未完成对象之前不可能删除它。

下面的代码失败并出现生命周期错误,因为它试图使 object 超出 factory 的生存期:

struct Object<'a> {
    factory: &'a Factory
}
struct Factory;

impl<'a> Object<'a> {
    pub fn new(factory: &Factory) -> Object { Object{factory} }
}

impl Factory {
    pub fn new() -> Factory { Factory{} }
    pub fn create(&self) -> Object { Object::new(self) }
}

fn main() {
    let _object = {
        let factory = Factory::new();
        let object = factory.create();
        object
    };
}

Keep a reference to the factory in the object. This will make it impossible to drop (or mutate) factory before its outstanding objects are dropped.

The code below fails with a lifetime error because it tries to make object outlive factory:

struct Object<'a> {
    factory: &'a Factory
}
struct Factory;

impl<'a> Object<'a> {
    pub fn new(factory: &Factory) -> Object { Object{factory} }
}

impl Factory {
    pub fn new() -> Factory { Factory{} }
    pub fn create(&self) -> Object { Object::new(self) }
}

fn main() {
    let _object = {
        let factory = Factory::new();
        let object = factory.create();
        object
    };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文