4

私は C ライブラリをラップしており、標準的な種類のコンテキスト オブジェクトがあります。

library_context* context = library_create_context();

そして、それを使用して、さらにオブジェクトを作成できます。

library_object* object = library_create_object(context);

そして、それらの両方を破壊します:

library_destroy_object(object);
library_destroy_context(context);

そこで、これを Rust 構造体にまとめました。

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

だから今、私はこれを行うことができ、うまくいくようです:

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

ただし、これを行うこともできます。

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

    do_something_with(ob);
}

つまり、ライブラリ コンテキストは、それが作成するオブジェクトが破棄される前に破棄されます。

Rust のライフタイム システムを使用して、上記のコードがコンパイルされないようにすることはできますか?

4

1 に答える 1

6

はい、通常のライフタイムを使用してください:

#[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たがりますが、私はここに利点があるかどうか確信が持てません:

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

#[derive(Debug)]
struct Object<'a> {
    marker: PhantomData<&'a ()>,
    raw_object: u8,
}
于 2016-12-13T21:15:50.630 に答える