本文介绍了限制Rust中的对象生存期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在包装一个C库,它具有标准的上下文对象:

I'm wrapping a C library, and it has a standard sort of context object:

library_context* context = library_create_context();

然后使用它可以创建更多对象:

And then using that you can create more objects:

library_object* object = library_create_object(context);

并摧毁它们两个:

library_destroy_object(object);
library_destroy_context(context);

因此,我将其包装在Rust结构中:

So I've wrapped this up in Rust structs:

struct Context {
    raw_context: *mut library_context,
}

impl Context {
    fn new() -> Context {
        Context {
            raw_context: unsafe { library_create_context() },
        }
    }

    fn create_object(&mut self) -> Object {
        Object {
            raw_object: unsafe { library_create_object(self.raw_context) },
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            library_context_destroy(self.raw_context);
        }
    }
}

struct Object {
    raw_object: *mut library_object,
}

impl Drop for Object {
    fn drop(&mut self) {
        unsafe {
            library_object_destroy(self.raw_object);
        }
    }
}

所以现在我可以执行此操作,并且它似乎可以工作:

So now I can do this, and it seems to work:

fn main() {
    let mut ctx = Context::new();
    let ob = ctx.create_object();
}

但是,我也可以这样做:

However, I can also do this:

fn main() {
    let mut ctx = Context::new();
    let ob = ctx.create_object();
    drop(ctx);

    do_something_with(ob);
}

即库上下文先于其创建的对象被销毁.

I.e. the library context is destroyed before the objects it creates are.

我可以以某种方式使用Rust的生命周期系统来防止上述代码编译吗?

Can I somehow use Rust's lifetime system to prevent the above code from compiling?

推荐答案

是的,请使用正常的生命周期:

Yes, just use normal lifetimes:

#[derive(Debug)]
struct Context(u8);

impl Context {
    fn new() -> Context {
        Context(0)
    }

    fn create_object(&mut self) -> Object {
        Object {
            context: self,
            raw_object: 1,
        }
    }
}

#[derive(Debug)]
struct Object<'a> {
    context: &'a Context,
    raw_object: u8,
}

fn main() {
    let mut ctx = Context::new();
    let ob = ctx.create_object();
    drop(ctx);

    println!("{:?}", ob);
}

这将失败

error[E0505]: cannot move out of `ctx` because it is borrowed
  --> src/main.rs:26:10
   |
25 |     let ob = ctx.create_object();
   |              --- borrow of `ctx` occurs here
26 |     drop(ctx);
   |          ^^^ move out of `ctx` occurs here

有时候人们喜欢使用 PhantomData ,但我不确定在这里是否看到好处:

Sometimes people like to use PhantomData, but I'm not sure I see the benefit here:

fn create_object(&mut self) -> Object {
    Object {
        marker: PhantomData,
        raw_object: 1,
    }
}

#[derive(Debug)]
struct Object<'a> {
    marker: PhantomData<&'a ()>,
    raw_object: u8,
}

这篇关于限制Rust中的对象生存期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 11:05