2016-12-13 4 views
2

ich Einwickeln einer C-Bibliothek, und es hat eine Standard-Art von Kontextobjekt:Beschränken Objektlebensdauern in Rust

library_context* context = library_create_context(); 

Und dann mit, dass Sie mehrere Objekte erstellen:

library_object* object = library_create_object(context); 

und zerstören sie beide:

library_destroy_object(object); 
library_destroy_context(context); 

Also habe ich diese structs in Rust verpackt:

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, jetzt kann ich dies tun, und es scheint zu funktionieren:

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

Allerdings kann ich auch dies tun:

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

    do_something_with(ob); 
} 

D.h. Der Bibliothekskontext wird zerstört, bevor die Objekte erstellt werden.

Kann ich irgendwie das Lebenszeit-System von Rust verwenden, um zu verhindern, dass der obige Code kompiliert wird?

+1

Bitte erstellen Sie ein [MCVE], wenn Sie Fragen stellen. Der angegebene Code schlägt mit 7 Fehlern nicht definierter Elemente fehl. Es ist auch möglich, dass du mehr ** M ** machen kannst, während du es ** C ** machst. – Shepmaster

Antwort

4

Ja, verwenden Sie nur normale Lebensdauer:

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

Dies wird nicht mit

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 

Manchmal sind die Leute PhantomData verwenden möchten, aber ich bin nicht sicher, ob ich den Vorteil hier sehen:

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

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

Aha Ich habe das versucht, aber habe es etwas falsch gemacht! Vielen Dank! – Timmmm

+0

@Timmmm beachte, dass die Wahl von '& mut self' für' create_object' bedeutet, dass du kein zweites Objekt erstellen kannst, da es so aussieht, als ob "Context" noch immer ausgeliehen ist und/oder du es nicht eine Sekunde mutieren könntest Zeit, da es noch einen unveränderlichen Kredit dazu gibt; nicht sicher, ob das mit Ihren Erwartungen übereinstimmt. – Shepmaster

+0

Ah, das erklärt das zweite Problem, das ich hatte. Gibt es eine Möglichkeit, die Mut-Eigenschaft zu entfernen, während die Funktion noch "& mut sel" hat? Etwas wie "Kontext: Selbst als & Kontext"? – Timmmm